diff --git a/packages/gluestick-cli/src/cli.js b/packages/gluestick-cli/src/cli.js index f5e757f3b..4baeabd05 100644 --- a/packages/gluestick-cli/src/cli.js +++ b/packages/gluestick-cli/src/cli.js @@ -51,6 +51,7 @@ commander .command('new') .description('generate a new application') .arguments('') + .option('-p, --preset ', 'specify preset to create project from') .option('-d, --dev ', 'relative path to development version of gluestick') .option('-s, --skip-main', 'gluestick will not generate main app') .option('-n, --npm', 'use npm instead of yarn') diff --git a/packages/gluestick-cli/src/new.js b/packages/gluestick-cli/src/new.js index 88bf713a5..f522257a7 100644 --- a/packages/gluestick-cli/src/new.js +++ b/packages/gluestick-cli/src/new.js @@ -9,35 +9,49 @@ const generate = require('gluestick-generators').default; const fetch = require('node-fetch'); const rimraf = require('rimraf'); +const ensureDevelopmentPathIsValid = (pathToGluestickRepo, exitWithError) => { + let gluestickPackage = {}; + try { + gluestickPackage = require(path.join(pathToGluestickRepo, 'package.json')); + } catch (error) { + exitWithError( + `Development GlueStick path ${pathToGluestickRepo} is not valid`, + ); + } + if (gluestickPackage.name !== 'gluestick-packages') { + exitWithError( + `${pathToGluestickRepo} is not a path to GlueStick`, + ); + } +}; + +const getDevelopmentDependencies = ({ dev }, pathToGluestickPackages) => { + return glob.sync('*', { cwd: pathToGluestickPackages }) + .filter(name => name !== 'gluestick-cli') + .reduce((acc, key) => { + return { ...acc, [key]: `file:${path.join('..', dev, 'packages', key)}` }; + }, {}); +}; + module.exports = (appName, options, exitWithError) => { - fetch('http://registry.npmjs.org/gluestick') - .then(res => res.json()) - .then(json => { - const packageDeps = { - dependencies: { - gluestick: json['dist-tags'].latest, - }, + const preset = options.preset || 'default'; + const api = 'http://registry.npmjs.org'; + Promise.all([ + fetch(`${api}/gluestick`), + fetch(`${api}/gluestick-preset-${preset}`), + ]).then(responses => Promise.all(responses.map(res => res.json()))) + .then(payloads => { + const latestGluestickVersion = payloads[0]['dist-tags'].latest; + const presetDependencies = payloads[1].versions[latestGluestickVersion].gsProjectDependencies; + let gluestickDependencies = { + gluestick: latestGluestickVersion, }; + if (options.dev) { const pathToGluestickRepo = path.join(process.cwd(), appName, '..', options.dev); const pathToGluestickPackages = path.join(pathToGluestickRepo, 'packages'); - let gluestickPackage = {}; - const packages = glob.sync('*', { cwd: pathToGluestickPackages }).filter((e) => e !== 'gluestick-cli'); - try { - gluestickPackage = require(path.join(pathToGluestickRepo, 'package.json')); - } catch (error) { - exitWithError( - `Development GlueStick path ${pathToGluestickRepo} is not valid`, - ); - } - if (gluestickPackage.name !== 'gluestick-packages') { - exitWithError( - `${pathToGluestickRepo} is not a path to GlueStick`, - ); - } - packages.forEach(e => { - packageDeps.dependencies[e] = `file:${path.join('..', options.dev, 'packages', e)}`; - }); + ensureDevelopmentPathIsValid(pathToGluestickRepo, exitWithError); + gluestickDependencies = getDevelopmentDependencies(options, pathToGluestickPackages); } const pathToApp = path.join(process.cwd(), appName); @@ -50,18 +64,24 @@ module.exports = (appName, options, exitWithError) => { mkdir.sync(path.join(process.cwd(), appName)); const generatorOptions = { - gluestickDependencies: packageDeps.dependencies, appName, + preset, + gluestickDependencies, + presetDependencies, }; process.chdir(appName); try { generate( { - generatorName: 'package', + generatorName: 'packageJson', entityName: 'package', options: generatorOptions, }, + undefined, + { + successMessageHandler: () => {}, + }, ); const isYarnAvailable = !spawn.sync('yarn', ['-V']).error; @@ -100,5 +120,12 @@ module.exports = (appName, options, exitWithError) => { console.error(error); process.exit(1); } + }) + .catch(error => { + console.error(chalk.red(error.message)); + console.error('This error may occur due to the following reasons:'); + console.error(` -> Cannot connect or make request to '${api}'`); + console.error(' -> Specified preset was not found'); + process.exit(1); }); }; diff --git a/packages/gluestick-generators/src/generators/packageJson.js b/packages/gluestick-generators/src/generators/packageJson.js new file mode 100644 index 000000000..7b9c93107 --- /dev/null +++ b/packages/gluestick-generators/src/generators/packageJson.js @@ -0,0 +1,58 @@ +/* DO NOT MODIFY */ +const createTemplate = module.parent.createTemplate; +/* END OF DO NOT MODIFY */ + +const dependenciesToJson = dependencies => (acc, key, index, array) => { + return acc.concat( + `"${key}": "${dependencies[key]}"${index === array.length - 1 ? '' : ',\n '}`, + ); +}; + +const templatePackage = createTemplate` +{ + "name": "${args => args.appName}", + "version": "1.0.0", + "description": "", + "main": "index.js", + "preset": "${args => args.preset}", + "scripts": { + "start": "gluestick start", + "test": "gluestick test", + "flow": "flow", + "lint": "eslint src" + }, + "dependencies": { + ${args => Object.keys(args.dependencies).reduce(dependenciesToJson(args.dependencies), '')} + }, + "devDependencies": { + ${args => Object.keys(args.devDependencies).reduce(dependenciesToJson(args.devDependencies), '')} + }, + "author": "", + "license": "ISC" +} +`; + +const reverseGluestickDependencies = dependencies => { + return Object.keys(dependencies).reverse().reduce((acc, key) => { + return { ...acc, [key]: dependencies[key] }; + }, {}); +}; + +module.exports = ({ appName, preset, gluestickDependencies, presetDependencies }) => ({ + entries: [ + { + path: '/', + filename: 'package.json', + template: templatePackage, + args: { + appName, + preset, + dependencies: { + ...reverseGluestickDependencies(gluestickDependencies), + ...presetDependencies.dependencies, + }, + devDependencies: presetDependencies.devDependencies, + }, + }, + ], +}); diff --git a/packages/gluestick-generators/src/requireGenerator.js b/packages/gluestick-generators/src/requireGenerator.js index d5e94a172..8a9cc42a0 100644 --- a/packages/gluestick-generators/src/requireGenerator.js +++ b/packages/gluestick-generators/src/requireGenerator.js @@ -8,10 +8,9 @@ const { convertToCamelCase, convertToKebabCase } = require('./utils'); // $FlowFixMe module.createTemplate = createTemplate; -const PATH_TO_GLUESTICK_TEMPLATES: string = '../../build/generator/predefined'; -const PATH_TO_GLUESTICK_CLI_TEMPLATES: string = '../templates'; +const PATH_TO_GLUESTICK_TEMPLATES: string = '../../build/generators/predefined'; const EXTERNAL: string = 'generators'; -const INTERNAL: string = './templates'; +const INTERNAL: string = './generators'; const safeResolve = (moduleToResolve: string, ...args: string[]): string => { try { @@ -27,8 +26,6 @@ const getPossiblePaths = (generatorName: string): string[] => { path.join(process.cwd(), `${EXTERNAL}/${convertToKebabCase(generatorName)}.js`), safeResolve('gluestick', PATH_TO_GLUESTICK_TEMPLATES, `${convertToCamelCase(generatorName)}.js`), safeResolve('gluestick', PATH_TO_GLUESTICK_TEMPLATES, `${convertToKebabCase(generatorName)}.js`), - safeResolve('gluestick-cli', PATH_TO_GLUESTICK_CLI_TEMPLATES, `${convertToCamelCase(generatorName)}.js`), - safeResolve('gluestick-cli', PATH_TO_GLUESTICK_CLI_TEMPLATES, `${convertToKebabCase(generatorName)}.js`), path.join(__dirname, INTERNAL, `${convertToCamelCase(generatorName)}.js`), path.join(__dirname, INTERNAL, `${convertToKebabCase(generatorName)}.js`), ]; diff --git a/packages/gluestick-generators/src/templates/package.js b/packages/gluestick-generators/src/templates/package.js deleted file mode 100644 index 9fed47e9c..000000000 --- a/packages/gluestick-generators/src/templates/package.js +++ /dev/null @@ -1,83 +0,0 @@ -/* DO NOT MODIFY */ -const createTemplate = module.parent.createTemplate; -/* END OF DO NOT MODIFY */ - -const templatePackage = createTemplate` -{ - "name": "${(args) => args.appName}", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "start": "gluestick start", - "test": "gluestick test", - "flow": "flow", - "lint": "eslint src" - }, - "dependencies": { - "babel-loader": "7.0.0", - "babel-plugin-transform-decorators-legacy": "1.3.4", - "babel-plugin-transform-flow-strip-types": "6.22.0", - "babel-polyfill": "6.23.0", - "babel-preset-es2015": "6.24.1", - "babel-preset-react": "6.24.1", - "babel-preset-stage-0": "6.24.1", - "css-loader": "0.28.1", - "extract-text-webpack-plugin": "2.1.0", - "file-loader": "0.11.1", - ${(args) => Object.keys(args.gluestickDependencies).reverse().reduce( - (prev, key, i, arr) => prev.concat( - `"${key}": "${args.gluestickDependencies[key]}",${i === arr.length - 1 ? '' : '\n '}`, - ), - '', - )} - "image-webpack-loader": "3.3.1", - "node-sass": "4.5.1", - "normalize.css": "^5.0.0", - "optimize-css-assets-webpack-plugin": "1.3.1", - "postcss-calc": "5.3.1", - "postcss-custom-properties": "5.0.2", - "postcss-loader": "1.3.3", - "react": "15.4.2", - "react-dom": "15.4.2", - "react-helmet": "4.0.0", - "react-hot-loader": "^3.0.0-beta.6", - "react-redux": "5.0.4", - "react-router": "3.0.2", - "react-router-scroll": "0.4.2", - "redux": "3.6.0", - "redux-thunk": "2.2.0", - "sass-loader": "6.0.3", - "style-loader": "0.16.1", - "url-loader": "0.5.8" - }, - "author": "", - "license": "ISC", - "devDependencies": { - "babel-eslint": "7.1.1", - "babel-jest": "18.0.0", - "babel-plugin-react-transform": "2.0.2", - "enzyme": "2.7.1", - "eslint": "3.14.1", - "eslint-plugin-react": "6.9.0", - "flow-bin": "0.45.0", - "flow-typed": "^2.0.0", - "react-addons-test-utils": "15.4.2", - "redbox-react": "1.3.3" - } -} -`; - -module.exports = ({ gluestickDependencies, appName }) => ({ - entries: [ - { - path: '/', - filename: 'package.json', - template: templatePackage, - args: { - gluestickDependencies, - appName, - }, - }, - ], -}); diff --git a/packages/gluestick-preset-default/.babelrc b/packages/gluestick-preset-default/.babelrc new file mode 100644 index 000000000..ca6f54ed1 --- /dev/null +++ b/packages/gluestick-preset-default/.babelrc @@ -0,0 +1,13 @@ +{ + "presets": [ + ["env", { + "targets": { + "node": 6.3 + } + }], + "stage-0" + ], + "plugins": [ + "transform-flow-strip-types" + ] +} diff --git a/packages/gluestick-preset-default/.npmignore b/packages/gluestick-preset-default/.npmignore new file mode 100644 index 000000000..06ebb4840 --- /dev/null +++ b/packages/gluestick-preset-default/.npmignore @@ -0,0 +1,5 @@ +**/__mocks__/** +**/__tests__/** +src/** +coverage/** +.babelrc \ No newline at end of file diff --git a/packages/gluestick-preset-default/package.json b/packages/gluestick-preset-default/package.json new file mode 100644 index 000000000..1c1b03827 --- /dev/null +++ b/packages/gluestick-preset-default/package.json @@ -0,0 +1,96 @@ +{ + "name": "gluestick-preset-default", + "version": "1.9.3", + "description": "The default preset for GlueStick project", + "main": "build/index.js", + "homepage": "https://github.com/TrueCar/gluestick", + "bugs": "https://github.com/TrueCar/gluestick/issues", + "license": "MIT", + "scripts": { + "test": "jest", + "test-coverage": "jest --coverage" + }, + "keywords": [ + "react", + "redux", + "jest", + "es6", + "es2015", + "universal", + "isomorphic", + "generator", + "boilerplate" + ], + "repository": { + "type": "git", + "url": "git@github.com:TrueCar/gluestick.git" + }, + "author": "Todd Williams ", + "peerDependencies": { + "gluestick": "1.9.3" + }, + "dependencies": { + "mkdirp": "^0.5.1" + }, + "devDependencies": { + "babel-plugin-transform-decorators-legacy": "1.3.4", + "babel-plugin-transform-flow-strip-types": "^6.22.0", + "babel-preset-es2015": "6.22.0", + "babel-preset-react": "6.22.0", + "babel-preset-stage-0": "6.22.0", + "gluestick": "1.9.3", + "jest": "19.0.0" + }, + "jest": { + "notify": true, + "testRegex": ".*/__tests__/.*\\.test\\.js$", + "roots": [ + "src" + ] + }, + "gsProjectDependencies": { + "dependencies": { + "babel-loader": "7.0.0", + "babel-plugin-transform-decorators-legacy": "1.3.4", + "babel-plugin-transform-flow-strip-types": "6.22.0", + "babel-polyfill": "6.23.0", + "babel-preset-es2015": "6.24.1", + "babel-preset-react": "6.24.1", + "babel-preset-stage-0": "6.24.1", + "css-loader": "0.28.1", + "extract-text-webpack-plugin": "2.1.0", + "file-loader": "0.11.1", + "image-webpack-loader": "3.3.1", + "node-sass": "4.5.1", + "normalize.css": "^5.0.0", + "optimize-css-assets-webpack-plugin": "1.3.1", + "postcss-calc": "5.3.1", + "postcss-custom-properties": "5.0.2", + "postcss-loader": "1.3.3", + "react": "15.4.2", + "react-dom": "15.4.2", + "react-helmet": "4.0.0", + "react-hot-loader": "^3.0.0-beta.6", + "react-redux": "5.0.4", + "react-router": "3.0.2", + "react-router-scroll": "0.4.2", + "redux": "3.6.0", + "redux-thunk": "2.2.0", + "sass-loader": "6.0.3", + "style-loader": "0.16.1", + "url-loader": "0.5.8" + }, + "devDependencies": { + "babel-eslint": "7.1.1", + "babel-jest": "18.0.0", + "babel-plugin-react-transform": "2.0.2", + "enzyme": "2.7.1", + "eslint": "3.14.1", + "eslint-plugin-react": "6.9.0", + "flow-bin": "0.45.0", + "flow-typed": "^2.0.0", + "react-addons-test-utils": "15.4.2", + "redbox-react": "1.3.3" + } + } +} diff --git a/packages/gluestick/src/generator/constants.js b/packages/gluestick-preset-default/src/constants.js similarity index 100% rename from packages/gluestick/src/generator/constants.js rename to packages/gluestick-preset-default/src/constants.js diff --git a/packages/gluestick/src/generator/predefined/__tests__/app.test.js b/packages/gluestick-preset-default/src/generators/__tests__/app.test.js similarity index 72% rename from packages/gluestick/src/generator/predefined/__tests__/app.test.js rename to packages/gluestick-preset-default/src/generators/__tests__/app.test.js index e79506be8..c2946c0d2 100644 --- a/packages/gluestick/src/generator/predefined/__tests__/app.test.js +++ b/packages/gluestick-preset-default/src/generators/__tests__/app.test.js @@ -1,19 +1,17 @@ /* @flow */ [ '../../templates/Index', - '../../templates/HomeTest', - '../../templates/MasterLayoutTest', - '../../templates/ContainerHomeTest', - '../../templates/NoMatchAppTest', - '../../templates/Empty', - '../../templates/Home', + '../../templates/empty', '../../templates/HomeCss.js', + '../../templates/routes', + '../../templates/reducersIndex', +].forEach(filename => jest.mock(filename, () => () => {})); +[ + '../../templates/Home', '../../templates/MasterLayout', - '../../templates/Routes', '../../templates/HomeApp', '../../templates/NoMatchApp', - '../../templates/Reducer', -].forEach(filename => jest.mock(filename, () => () => {})); +].forEach(filename => jest.mock(filename, () => ({ source: () => {}, test: () => {} }))); const appGenerator = require('../app'); const mockFlowConfig = (mapper = '') => ` @@ -40,16 +38,21 @@ ${mapper} ^0.38.0 `; +const utils = { + ...require('gluestick/build/utils'), + createTemplate: v => v, +}; + describe('generator/predefined/app', () => { it('should modify flowconfig', () => { - const modifier: Function = appGenerator({ name: 'appName' }).modify[1].modifier; + const modifier: Function = appGenerator(utils)({ name: 'appName' }).modify[1].modifier; expect(modifier(mockFlowConfig())).toEqual(mockFlowConfig( 'module.name_mapper=\'^appName/\\(.*\\)\'->\'/src/apps/app-name/\\1\'\n\n', )); }); it('should not modify flowconfig', () => { - const modifier: Function = appGenerator({ name: 'appName' }).modify[1].modifier; + const modifier: Function = appGenerator(utils)({ name: 'appName' }).modify[1].modifier; expect(modifier(mockFlowConfig( 'module.name_mapper=\'^appName/\\(.*\\)\'->\'/src/apps/app-name/\\1\'', ))).toEqual(mockFlowConfig( @@ -58,14 +61,14 @@ describe('generator/predefined/app', () => { }); it('should throw error', () => { - const modifier: Function = appGenerator({ name: 'appName' }).modify[1].modifier; + const modifier: Function = appGenerator(utils)({ name: 'appName' }).modify[1].modifier; expect(() => { modifier(); }).toThrowError('Generating new app without bootstraped project'); }); it('should modify entries.json', () => { - const modifier: Function = appGenerator({ name: 'appName' }).modify[0].modifier; + const modifier: Function = appGenerator(utils)({ name: 'appName' }).modify[0].modifier; expect(modifier('{}')).toEqual(JSON.stringify({ '/app-name': { name: 'appName', diff --git a/packages/gluestick/src/generator/predefined/app.js b/packages/gluestick-preset-default/src/generators/app.js similarity index 67% rename from packages/gluestick/src/generator/predefined/app.js rename to packages/gluestick-preset-default/src/generators/app.js index 5e16711f1..a5bff45fe 100644 --- a/packages/gluestick/src/generator/predefined/app.js +++ b/packages/gluestick-preset-default/src/generators/app.js @@ -1,26 +1,20 @@ /* @flow */ -import type { GeneratorOptions } from '../../types'; +import type { PredefinedGeneratorOptions, GeneratorUtils } from '../types'; -/* DO NOT MODIFY */ -const createTemplate = module.parent.createTemplate; -/* END OF DO NOT MODIFY */ +const templateIndex = require('../templates/Index'); +const templateEmpty = require('../templates/empty'); +const templateHomeCss = require('../templates/HomeCss.js'); +const templateRoutes = require('../templates/routes'); +const templateHome = require('../templates/Home'); -const templateIndex = require('../templates/Index')(createTemplate); -const templateHomeTest = require('../templates/HomeTest')(createTemplate); -const templateMasterLayoutTest = require('../templates/MasterLayoutTest')(createTemplate); -const templateContainerHomeTest = require('../templates/ContainerHomeTest')(createTemplate); -const templateNoMatchAppTest = require('../templates/NoMatchAppTest')(createTemplate); -const templateEmpty = require('../templates/Empty')(createTemplate); -const templateHome = require('../templates/Home')(createTemplate); -const templateHomeCss = require('../templates/HomeCss.js')(createTemplate); -const templateMasterLayout = require('../templates/MasterLayout')(createTemplate); -const templateRoutes = require('../templates/Routes')(createTemplate); -const templateHomeApp = require('../templates/HomeApp')(createTemplate); -const templateNoMatchApp = require('../templates/NoMatchApp')(createTemplate); -const templateReducer = require('../templates/Reducer')(createTemplate); -const { convertToCamelCase, convertToKebabCase } = require('../../utils'); +const templateMasterLayout = require('../templates/MasterLayout'); +const templateHomeApp = require('../templates/HomeApp'); +const templateNoMatchApp = require('../templates/NoMatchApp'); +const templateReducer = require('../templates/reducersIndex'); -module.exports = (options: GeneratorOptions) => { +module.exports = ( + { convertToCamelCase, convertToKebabCase, createTemplate }: GeneratorUtils, +) => (options: PredefinedGeneratorOptions) => { const appName = convertToKebabCase(options.name); return ({ modify: [{ @@ -73,7 +67,7 @@ module.exports = (options: GeneratorOptions) => { { path: `src/apps/${options.name}`, filename: 'routes.js', - template: templateRoutes, + template: templateRoutes(createTemplate), args: { index: appName, }, @@ -81,72 +75,72 @@ module.exports = (options: GeneratorOptions) => { { path: `src/apps/${options.name}`, filename: 'Index.js', - template: templateIndex, + template: templateIndex(createTemplate), }, { path: `src/apps/${options.name}/components`, filename: 'Home.js', - template: templateHome, + template: templateHome.source(createTemplate), + }, + { + path: `src/apps/${options.name}/components/__tests__`, + filename: 'Home.test.js', + template: templateHome.test(createTemplate), }, { path: `src/apps/${options.name}/components`, filename: 'Home.css', - template: templateHomeCss, + template: templateHomeCss(createTemplate), }, { path: `src/apps/${options.name}/components`, filename: 'MasterLayout.js', - template: templateMasterLayout, + template: templateMasterLayout.source(createTemplate), }, { - path: `src/apps/${options.name}/containers`, - filename: 'HomeApp.js', - template: templateHomeApp, + path: `src/apps/${options.name}/components/__tests__`, + filename: 'MasterLayout.test.js', + template: templateMasterLayout.test(createTemplate), }, { path: `src/apps/${options.name}/containers`, - filename: 'NoMatchApp.js', - template: templateNoMatchApp, + filename: 'HomeApp.js', + template: templateHomeApp.source(createTemplate), }, { - path: `src/apps/${options.name}/actions`, - filename: '.gitkeep', - template: templateEmpty, + path: `src/apps/${options.name}/containers/__tests__`, + filename: 'HomeApp.test.js', + template: templateHomeApp.test(createTemplate), }, { - path: `src/apps/${options.name}/reducers`, - filename: 'index.js', - template: templateReducer, + path: `src/apps/${options.name}/containers`, + filename: 'NoMatchApp.js', + template: templateNoMatchApp.source(createTemplate), }, { - path: `src/apps/${options.name}/components/__tests__`, - filename: 'Home.test.js', - template: templateHomeTest, + path: `src/apps/${options.name}/containers/__tests__`, + filename: 'NoMatchApp.test.js', + template: templateNoMatchApp.test(createTemplate), }, { - path: `src/apps/${options.name}/components/__tests__`, - filename: 'MasterLayout.test.js', - template: templateMasterLayoutTest, + path: `src/apps/${options.name}/actions`, + filename: '.gitkeep', + template: templateEmpty(createTemplate), }, { - path: `src/apps/${options.name}/containers/__tests__`, - filename: 'HomeApp.test.js', - template: templateContainerHomeTest, + path: `src/apps/${options.name}/actions/__tests__`, + filename: '.gitkeep', + template: templateEmpty(createTemplate), }, { - path: `src/apps/${options.name}/containers/__tests__`, - filename: 'NoMatchApp.test.js', - template: templateNoMatchAppTest, + path: `src/apps/${options.name}/reducers`, + filename: 'index.js', + template: templateReducer(createTemplate), }, { path: `src/apps/${options.name}/reducers/__tests__`, filename: '.gitkeep', - template: templateEmpty, - }, - { - path: `src/apps/${options.name}/actions/__tests__`, - filename: '.gitkeep', - template: templateEmpty, + template: templateEmpty(createTemplate), }, ], }); diff --git a/packages/gluestick/src/generator/predefined/component.js b/packages/gluestick-preset-default/src/generators/component.js similarity index 69% rename from packages/gluestick/src/generator/predefined/component.js rename to packages/gluestick-preset-default/src/generators/component.js index 584881c43..801f821a4 100644 --- a/packages/gluestick/src/generator/predefined/component.js +++ b/packages/gluestick-preset-default/src/generators/component.js @@ -1,13 +1,10 @@ /* @flow */ -import type { PredefinedGeneratorOptions } from '../../types'; +import type { PredefinedGeneratorOptions, GeneratorUtils } from '../types'; const path = require('path'); -const { convertToPascalCase } = require('../../utils'); -const createTemplate = module.parent.createTemplate; - -const classComponentTemplate = createTemplate` +const getClassComponentTemplate = createTemplate => createTemplate` /* @flow */ import React, { Component } from "react"; @@ -23,7 +20,7 @@ export default class ${args => args.name} extends Component { } `; -const functionalComponentTemplate = createTemplate` +const getFunctionalComponentTemplate = createTemplate => createTemplate` /* @flow */ import React from "react"; @@ -37,7 +34,7 @@ export default function ${args => args.name} () { } `; -const testTemplate = createTemplate` +const getTestTemplate = createTemplate => createTemplate` import React from "react"; import { shallow } from "enzyme"; @@ -52,7 +49,9 @@ describe("${args => args.path}", () => { }); `; -module.exports = (options: PredefinedGeneratorOptions) => { +module.exports = ( + { convertToPascalCase, createTemplate }: GeneratorUtils, +) => (options: PredefinedGeneratorOptions) => { const rewrittenName = convertToPascalCase(options.name); const directoryPrefix = options.dir && options.dir !== '.' ? `${options.dir}/` : ''; @@ -64,12 +63,14 @@ module.exports = (options: PredefinedGeneratorOptions) => { { path: path.join('src', options.entryPoint, 'components', directoryPrefix), filename: rewrittenName, - template: options.functional ? functionalComponentTemplate : classComponentTemplate, + template: options.functional + ? getFunctionalComponentTemplate(createTemplate) + : getClassComponentTemplate(createTemplate), }, { path: path.join('src', options.entryPoint, 'components', directoryPrefix, '__tests__'), filename: `${rewrittenName}.test.js`, - template: testTemplate, + template: getTestTemplate(createTemplate), args: { path: path.join(options.entryPoint, 'components', directoryPrefix, rewrittenName), }, diff --git a/packages/gluestick/src/generator/predefined/container.js b/packages/gluestick-preset-default/src/generators/container.js similarity index 84% rename from packages/gluestick/src/generator/predefined/container.js rename to packages/gluestick-preset-default/src/generators/container.js index a6ba5ebc9..5f41a8c72 100644 --- a/packages/gluestick/src/generator/predefined/container.js +++ b/packages/gluestick-preset-default/src/generators/container.js @@ -1,13 +1,10 @@ /* @flow */ -import type { PredefinedGeneratorOptions } from '../../types'; +import type { PredefinedGeneratorOptions, GeneratorUtils } from '../types'; const path = require('path'); -const { convertToPascalCase } = require('../../utils'); -const createTemplate = module.parent.createTemplate; - -const containerTemplate = createTemplate` +const getContainerTemplate = createTemplate => createTemplate` /* @flow */ import React, { Component } from "react"; @@ -48,7 +45,7 @@ export default connect( )(${args => args.name}); `; -const testTemplate = createTemplate` +const getTestTemplate = createTemplate => createTemplate` /* @flow */ import React from "react"; @@ -65,7 +62,9 @@ describe("${args => args.path}", () => { }); `; -module.exports = (options: PredefinedGeneratorOptions) => { +module.exports = ( + { convertToPascalCase, createTemplate }: GeneratorUtils, +) => (options: PredefinedGeneratorOptions) => { const rewrittenName = convertToPascalCase(options.name); const directoryPrefix = options.dir && options.dir !== '.' ? `${options.dir}/` : ''; return { @@ -76,12 +75,12 @@ module.exports = (options: PredefinedGeneratorOptions) => { { path: path.join('src', options.entryPoint, 'containers', directoryPrefix), filename: rewrittenName, - template: containerTemplate, + template: getContainerTemplate(createTemplate), }, { path: path.join('src', options.entryPoint, 'containers', directoryPrefix, '__tests__'), filename: `${rewrittenName}.test.js`, - template: testTemplate, + template: getTestTemplate(createTemplate), args: { path: path.join(options.entryPoint, 'containers', directoryPrefix, rewrittenName), }, diff --git a/packages/gluestick-preset-default/src/generators/new.js b/packages/gluestick-preset-default/src/generators/new.js new file mode 100644 index 000000000..e0bad467c --- /dev/null +++ b/packages/gluestick-preset-default/src/generators/new.js @@ -0,0 +1,180 @@ +/* @flow */ +import type { PredefinedGeneratorOptions, GeneratorUtils } from '../types'; + +const templateEslintrc = require('../templates/_eslintrc'); +const templateFlowConfig = require('../templates/_flowconfig'); +const templateBabelrc = require('../templates/babelrc'); +const templateEmpty = require('../templates/empty'); +const templateEntries = require('../templates/entries'); +const templateIndex = require('../templates/Index'); + +const templateHome = require('../templates/Home'); +const templateHomeApp = require('../templates/HomeApp'); +const templateHomeCss = require('../templates/HomeCss.js'); +const templateMasterLayout = require('../templates/MasterLayout'); +const templateNoMatchApp = require('../templates/NoMatchApp'); +const templateReducer = require('../templates/reducersIndex'); +const templateRoutes = require('../templates/routes'); + + +const { flowVersion, flowMapper } = require('../constants'); + +module.exports = ({ createTemplate }: GeneratorUtils) => (options: PredefinedGeneratorOptions) => { + const entries = [ + { + path: '/', + filename: '.eslintrc', + template: templateEslintrc(createTemplate), + }, + { + path: '/', + filename: '.flowconfig', + template: templateFlowConfig(createTemplate), + args: { + appName: options.appName, + version: flowVersion, + mapper: flowMapper, + }, + }, + { + path: '/', + filename: '.babelrc', + template: templateBabelrc(createTemplate), + }, + { + path: 'src', + filename: 'entries.json', + template: templateEntries(createTemplate), + }, + // Shared + { + path: 'src/shared/actions', + filename: '.gitkeep', + template: templateEmpty(createTemplate), + }, + { + path: 'src/shared/actions/__tests__', + filename: '.gitkeep', + template: templateEmpty(createTemplate), + }, + { + path: 'src/shared/components', + filename: '.gitkeep', + template: templateEmpty(createTemplate), + }, + { + path: 'src/shared/components/__tests__', + filename: '.gitkeep', + template: templateEmpty(createTemplate), + }, + { + path: 'src/shared/containers', + filename: '.gitkeep', + template: templateEmpty(createTemplate), + }, + { + path: 'src/shared/containers/__tests__', + filename: '.gitkeep', + template: templateEmpty(createTemplate), + }, + { + path: 'src/shared/assets', + filename: '.gitkeep', + template: templateEmpty(createTemplate), + }, + { + path: 'src/shared/reducers', + filename: '.gitkeep', + template: templateEmpty(createTemplate), + }, + { + path: 'src/shared/reducers/__tests__', + filename: '.gitkeep', + template: templateEmpty(createTemplate), + }, + // Main app + { + path: 'src/apps/main/assets', + filename: '.gitkeep', + template: templateEmpty(createTemplate), + }, + { + path: 'src/apps/main', + filename: 'routes.js', + template: templateRoutes(createTemplate), + }, + { + path: 'src/apps/main', + filename: 'Index.js', + template: templateIndex(createTemplate), + }, + { + path: 'src/apps/main/components', + filename: 'Home.js', + template: templateHome.source(createTemplate), + }, + { + path: 'src/apps/main/components/__tests__', + filename: 'Home.test.js', + template: templateHome.test(createTemplate), + }, + { + path: 'src/apps/main/components', + filename: 'Home.css', + template: templateHomeCss(createTemplate), + }, + { + path: 'src/apps/main/components', + filename: 'MasterLayout.js', + template: templateMasterLayout.source(createTemplate), + }, + { + path: 'src/apps/main/components/__tests__', + filename: 'MasterLayout.test.js', + template: templateMasterLayout.test(createTemplate), + }, + { + path: 'src/apps/main/containers', + filename: 'HomeApp.js', + template: templateHomeApp.source(createTemplate), + }, + { + path: 'src/apps/main/containers/__tests__', + filename: 'HomeApp.test.js', + template: templateHomeApp.test(createTemplate), + }, + { + path: 'src/apps/main/containers', + filename: 'NoMatchApp.js', + template: templateNoMatchApp.source(createTemplate), + }, + { + path: 'src/apps/main/containers/__tests__', + filename: 'NoMatchApp.test.js', + template: templateNoMatchApp.test(createTemplate), + }, + { + path: 'src/apps/main/actions', + filename: '.gitkeep', + template: templateEmpty(createTemplate), + }, + { + path: 'src/apps/main/reducers', + filename: 'index.js', + template: templateReducer(createTemplate), + }, + { + path: 'src/apps/main/reducers/__tests__', + filename: '.gitkeep', + template: templateEmpty(createTemplate), + }, + { + path: 'src/apps/main/actions/__tests__', + filename: '.gitkeep', + template: templateEmpty(createTemplate), + }, + ]; + return { + entries: options.skipMain ? entries.filter(o => !o.path.includes('apps/main')) : entries, + }; +}; diff --git a/packages/gluestick/src/generator/predefined/reducer.js b/packages/gluestick-preset-default/src/generators/reducer.js similarity index 82% rename from packages/gluestick/src/generator/predefined/reducer.js rename to packages/gluestick-preset-default/src/generators/reducer.js index 084bd9688..7843a8f81 100644 --- a/packages/gluestick/src/generator/predefined/reducer.js +++ b/packages/gluestick-preset-default/src/generators/reducer.js @@ -1,13 +1,10 @@ /* @flow */ -import type { PredefinedGeneratorOptions } from '../../types'; +import type { PredefinedGeneratorOptions, GeneratorUtils } from '../types'; const path = require('path'); -const { convertToCamelCase, convertToCamelCaseWithPrefix } = require('../../utils'); -const createTemplate = module.parent.createTemplate; - -const reducerTemplate = createTemplate` +const getReducerTemplate = createTemplate => createTemplate` /* @flow */ type State = { @@ -24,7 +21,7 @@ export default (state: State = INITIAL_STATE, action: { type: string, payload?: }; `; -const testTemplate = createTemplate` +const getTestTemplate = createTemplate => createTemplate` /* @flow */ import reducer from "${args => args.path}"; @@ -43,7 +40,9 @@ describe("${args => args.path}", () => { const getReducerImport = (name, dir) => `import ${name} from "./${dir}";`; -module.exports = (options: PredefinedGeneratorOptions) => { +module.exports = ( + { convertToCamelCase, convertToCamelCaseWithPrefix, createTemplate }: GeneratorUtils, +) => (options: PredefinedGeneratorOptions) => { const rewrittenName = convertToCamelCase(options.name); const directoryPrefix = options.dir && options.dir !== '.' ? `${options.dir}/` : ''; return { @@ -70,12 +69,12 @@ module.exports = (options: PredefinedGeneratorOptions) => { { path: path.join('src', options.entryPoint, 'reducers', directoryPrefix), filename: rewrittenName, - template: reducerTemplate, + template: getReducerTemplate(createTemplate), }, { path: path.join('src', options.entryPoint, 'reducers', directoryPrefix, '__tests__'), filename: `${rewrittenName}.test.js`, - template: testTemplate, + template: getTestTemplate(createTemplate), args: { path: path.join(options.entryPoint, 'reducers', directoryPrefix, rewrittenName), }, diff --git a/packages/gluestick/src/generator/templates/Home.js b/packages/gluestick-preset-default/src/templates/Home.js similarity index 68% rename from packages/gluestick/src/generator/templates/Home.js rename to packages/gluestick-preset-default/src/templates/Home.js index 8c571abb6..4866b5b48 100644 --- a/packages/gluestick/src/generator/templates/Home.js +++ b/packages/gluestick-preset-default/src/templates/Home.js @@ -1,7 +1,7 @@ /* @flow */ -import type { CreateTemplate } from '../../types'; +import type { CreateTemplate } from '../types'; -module.exports = (createTemplate: CreateTemplate) => createTemplate` +module.exports.source = (createTemplate: CreateTemplate) => createTemplate` /* @flow */ import React, { Component } from "react"; @@ -41,3 +41,20 @@ export default class Home extends Component { } } `; + +module.exports.test = (createTemplate: CreateTemplate) => createTemplate` +/* @flow */ + +import React from "react"; +import { shallow } from "enzyme"; + +import Home from "../Home"; + +describe("components/Home", () => { + it("renders without an issue", () => { + const subject = ; + const wrapper = shallow(subject); + expect(wrapper).toBeDefined(); + }); +}); +`; diff --git a/packages/gluestick/src/generator/templates/HomeApp.js b/packages/gluestick-preset-default/src/templates/HomeApp.js similarity index 72% rename from packages/gluestick/src/generator/templates/HomeApp.js rename to packages/gluestick-preset-default/src/templates/HomeApp.js index 3504762a6..61429be38 100644 --- a/packages/gluestick/src/generator/templates/HomeApp.js +++ b/packages/gluestick-preset-default/src/templates/HomeApp.js @@ -1,7 +1,7 @@ /* @flow */ -import type { CreateTemplate } from '../../types'; +import type { CreateTemplate } from '../types'; -module.exports = (createTemplate: CreateTemplate) => createTemplate` +module.exports.source = (createTemplate: CreateTemplate) => createTemplate` /* @flow */ import React, { Component } from "react"; @@ -44,3 +44,20 @@ export default connect( )(HomeApp); `; + +module.exports.test = (createTemplate: CreateTemplate) => createTemplate` +/* @flow */ + +import React from "react"; +import { shallow } from "enzyme"; + +import { HomeApp } from "../HomeApp"; + +describe("containers/HomeApp", () => { + it("renders without an issue", () => { + const subject = ; + const wrapper = shallow(subject); + expect(wrapper).toBeDefined(); + }); +}); +`; diff --git a/packages/gluestick/src/generator/templates/HomeCss.js b/packages/gluestick-preset-default/src/templates/HomeCss.js similarity index 91% rename from packages/gluestick/src/generator/templates/HomeCss.js rename to packages/gluestick-preset-default/src/templates/HomeCss.js index 5de82237b..6284cea4a 100644 --- a/packages/gluestick/src/generator/templates/HomeCss.js +++ b/packages/gluestick-preset-default/src/templates/HomeCss.js @@ -1,5 +1,5 @@ /* @flow */ -import type { CreateTemplate } from '../../types'; +import type { CreateTemplate } from '../types'; module.exports = (createTemplate: CreateTemplate) => createTemplate` .Home-header { diff --git a/packages/gluestick/src/generator/templates/Index.js b/packages/gluestick-preset-default/src/templates/Index.js similarity index 96% rename from packages/gluestick/src/generator/templates/Index.js rename to packages/gluestick-preset-default/src/templates/Index.js index 6837e48cc..cc090f954 100644 --- a/packages/gluestick/src/generator/templates/Index.js +++ b/packages/gluestick-preset-default/src/templates/Index.js @@ -1,5 +1,5 @@ /* @flow */ -import type { CreateTemplate } from '../../types'; +import type { CreateTemplate } from '../types'; module.exports = (createTemplate: CreateTemplate) => createTemplate` /* @flow */ diff --git a/packages/gluestick-preset-default/src/templates/MasterLayout.js b/packages/gluestick-preset-default/src/templates/MasterLayout.js new file mode 100644 index 000000000..b631b622f --- /dev/null +++ b/packages/gluestick-preset-default/src/templates/MasterLayout.js @@ -0,0 +1,42 @@ +/* @flow */ +import type { CreateTemplate } from '../types'; + +module.exports.source = (createTemplate: CreateTemplate) => createTemplate` +/* @flow */ + +import React, { Component, PropTypes } from "react"; +import Helmet from "react-helmet"; +import config from "config/application"; + +export default class MasterLayout extends Component { + static propTypes = { + children: PropTypes.any + }; + + render () { + return ( +
+ + {this.props.children} +
+ ); + } +} +`; + +module.exports.test = (createTemplate: CreateTemplate) => createTemplate` +/* @flow */ + +import React from "react"; +import { shallow } from "enzyme"; + +import MasterLayout from "../MasterLayout"; + +describe("components/MasterLayout", () => { + it("renders without an issue", () => { + const subject = ; + const wrapper = shallow(subject); + expect(wrapper).toBeDefined(); + }); +}); +`; diff --git a/packages/gluestick/src/generator/templates/NoMatchApp.js b/packages/gluestick-preset-default/src/templates/NoMatchApp.js similarity index 71% rename from packages/gluestick/src/generator/templates/NoMatchApp.js rename to packages/gluestick-preset-default/src/templates/NoMatchApp.js index 566b10f87..7d66e74a0 100644 --- a/packages/gluestick/src/generator/templates/NoMatchApp.js +++ b/packages/gluestick-preset-default/src/templates/NoMatchApp.js @@ -1,7 +1,7 @@ /* @flow */ -import type { CreateTemplate } from '../../types'; +import type { CreateTemplate } from '../types'; -module.exports = (createTemplate: CreateTemplate) => createTemplate` +module.exports.source = (createTemplate: CreateTemplate) => createTemplate` /* @flow */ import React, { Component } from "react"; @@ -41,3 +41,20 @@ export default connect( (dispatch) => bindActionCreators({/** _INSERT_ACTION_CREATORS_ **/}, dispatch) )(NoMatchApp); `; + +module.exports.test = (createTemplate: CreateTemplate) => createTemplate` +/* @flow */ + +import React from "react"; +import { shallow } from "enzyme"; + +import { NoMatchApp } from "../NoMatchApp"; + +describe("containers/NoMatchApp", () => { + it("renders without an issue", () => { + const subject = ; + const wrapper = shallow(subject); + expect(wrapper).toBeDefined(); + }); +}); +`; diff --git a/packages/gluestick/src/generator/templates/_eslintrc.js b/packages/gluestick-preset-default/src/templates/_eslintrc.js similarity index 95% rename from packages/gluestick/src/generator/templates/_eslintrc.js rename to packages/gluestick-preset-default/src/templates/_eslintrc.js index 169bd1b1e..7f2885f9a 100644 --- a/packages/gluestick/src/generator/templates/_eslintrc.js +++ b/packages/gluestick-preset-default/src/templates/_eslintrc.js @@ -1,5 +1,5 @@ /* @flow */ -import type { CreateTemplate } from '../../types'; +import type { CreateTemplate } from '../types'; module.exports = (createTemplate: CreateTemplate) => createTemplate` { diff --git a/packages/gluestick/src/generator/templates/_flowconfig.js b/packages/gluestick-preset-default/src/templates/_flowconfig.js similarity index 92% rename from packages/gluestick/src/generator/templates/_flowconfig.js rename to packages/gluestick-preset-default/src/templates/_flowconfig.js index 030a910c1..2783aacea 100644 --- a/packages/gluestick/src/generator/templates/_flowconfig.js +++ b/packages/gluestick-preset-default/src/templates/_flowconfig.js @@ -1,6 +1,6 @@ /* @flow */ -import type { CreateTemplate } from '../../types'; +import type { CreateTemplate } from '../types'; module.exports = (createTemplate: CreateTemplate) => createTemplate` [ignore] diff --git a/packages/gluestick-preset-default/src/templates/babelrc.js b/packages/gluestick-preset-default/src/templates/babelrc.js new file mode 100644 index 000000000..88d5ad8a9 --- /dev/null +++ b/packages/gluestick-preset-default/src/templates/babelrc.js @@ -0,0 +1,12 @@ +/* @flow */ +import type { CreateTemplate } from '../types'; + +module.exports = (createTemplate: CreateTemplate) => createTemplate` +{ + "presets": [ + "react", + "es2015", + "stage-0" + ] +} +`; diff --git a/packages/gluestick/src/generator/templates/Empty.js b/packages/gluestick-preset-default/src/templates/empty.js similarity index 73% rename from packages/gluestick/src/generator/templates/Empty.js rename to packages/gluestick-preset-default/src/templates/empty.js index 82171108c..3b0ab7408 100644 --- a/packages/gluestick/src/generator/templates/Empty.js +++ b/packages/gluestick-preset-default/src/templates/empty.js @@ -1,5 +1,5 @@ /* @flow */ -import type { CreateTemplate } from '../../types'; +import type { CreateTemplate } from '../types'; module.exports = (createTemplate: CreateTemplate) => createTemplate` this file exists so npm will include the empty folder diff --git a/packages/gluestick/src/generator/templates/entries.js b/packages/gluestick-preset-default/src/templates/entries.js similarity index 81% rename from packages/gluestick/src/generator/templates/entries.js rename to packages/gluestick-preset-default/src/templates/entries.js index f734e7fe9..baca3f806 100644 --- a/packages/gluestick/src/generator/templates/entries.js +++ b/packages/gluestick-preset-default/src/templates/entries.js @@ -1,5 +1,5 @@ /* @flow */ -import type { CreateTemplate } from '../../types'; +import type { CreateTemplate } from '../types'; module.exports = (createTemplate: CreateTemplate) => createTemplate` { diff --git a/packages/gluestick/src/generator/templates/Reducer.js b/packages/gluestick-preset-default/src/templates/reducersIndex.js similarity index 69% rename from packages/gluestick/src/generator/templates/Reducer.js rename to packages/gluestick-preset-default/src/templates/reducersIndex.js index 1326bab65..e6b94149c 100644 --- a/packages/gluestick/src/generator/templates/Reducer.js +++ b/packages/gluestick-preset-default/src/templates/reducersIndex.js @@ -1,5 +1,5 @@ /* @flow */ -import type { CreateTemplate } from '../../types'; +import type { CreateTemplate } from '../types'; module.exports = (createTemplate: CreateTemplate) => createTemplate` /* @flow */ diff --git a/packages/gluestick/src/generator/templates/Routes.js b/packages/gluestick-preset-default/src/templates/routes.js similarity index 93% rename from packages/gluestick/src/generator/templates/Routes.js rename to packages/gluestick-preset-default/src/templates/routes.js index 566e2569d..1c39802a5 100644 --- a/packages/gluestick/src/generator/templates/Routes.js +++ b/packages/gluestick-preset-default/src/templates/routes.js @@ -1,5 +1,5 @@ /* @flow */ -import type { CreateTemplate } from '../../types'; +import type { CreateTemplate } from '../types'; module.exports = (createTemplate: CreateTemplate) => createTemplate` /* @flow */ diff --git a/packages/gluestick-preset-default/src/types.js b/packages/gluestick-preset-default/src/types.js new file mode 100644 index 000000000..c79990b26 --- /dev/null +++ b/packages/gluestick-preset-default/src/types.js @@ -0,0 +1,20 @@ +export type CreateTemplate = ( + interpolations: Array<*>, + strings: Array, +) => (args: Object) => string; + +export type GeneratorOptions = { + [key: string]: any; +}; + +export type GeneratorUtils = { + convertToCamelCase: Function; + convertToKebabCase: Function; + createTemplate: Function; +}; + +export type PredefinedGeneratorOptions = { + name: string; + dir?: string; + entryPoint: string; +}; diff --git a/packages/gluestick/src/cli/commandApi.js b/packages/gluestick/src/cli/commandApi.js index 6f4245114..bb3e615b3 100644 --- a/packages/gluestick/src/cli/commandApi.js +++ b/packages/gluestick/src/cli/commandApi.js @@ -43,9 +43,9 @@ const getPlugins = ( // Compile gluestick config const getGluestickConfig = ( - logger: Logger, plugins: ConfigPlugin[], + logger: Logger, plugins: ConfigPlugin[], options: { [key: string]: any } = {}, ): GSConfig => { - const config: GSConfig = compileGlueStickConfig(logger, plugins); + const config: GSConfig = compileGlueStickConfig(logger, plugins, options); // $FlowIgnore get additional data from a property config.pluginsConfigPath = plugins.pluginsConfigPath; return config; diff --git a/packages/gluestick/src/commands/autoUpgrade/__tests__/autoUpgrade.test.js b/packages/gluestick/src/commands/autoUpgrade/__tests__/autoUpgrade.test.js index 521640e0e..f35a92655 100644 --- a/packages/gluestick/src/commands/autoUpgrade/__tests__/autoUpgrade.test.js +++ b/packages/gluestick/src/commands/autoUpgrade/__tests__/autoUpgrade.test.js @@ -18,11 +18,11 @@ jest.mock('gluestick-generators', () => ({ }), ), })); -jest.mock('../updateDependencies.js', () => jest.fn()); +jest.mock('../checkForMismatch.js', () => jest.fn(() => Promise.resolve({ shouldFix: false }))); const fs = require('fs'); const path = require('path'); const autoUpgrade = require('../autoUpgrade'); -const updateDependencies = require('../updateDependencies'); +const checkForMismatch = require('../checkForMismatch'); const originalPathJoin = path.join.bind(path); const getContext = (config) => ({ @@ -41,6 +41,8 @@ describe('autoUpgrade/index', () => { fs.writeFileSync.mockClear(); fs.existsSync.mockClear(); fs.readFileSync.mockClear(); + // $FlowIgnore checkForMismatch is mocked + checkForMismatch.mockClear(); }); afterAll(() => { @@ -54,7 +56,7 @@ describe('autoUpgrade/index', () => { await autoUpgrade(getContext({ changed: ['file-0'], added: ['file-0'], - }), false); + })); expect(fs.existsSync.mock.calls[0][0]).toEqual('file-0'); expect(fs.writeFileSync.mock.calls.length).toBe(0); }); @@ -64,20 +66,21 @@ describe('autoUpgrade/index', () => { await autoUpgrade(getContext({ changed: ['file-1'], added: ['file-1'], - }), false); + })); expect(fs.existsSync.mock.calls[0][0]).toEqual('file-1'); expect(fs.writeFileSync.mock.calls).toEqual([ ['file-1', 'file-0', 'utf-8'], ['file-1', 'file-0', 'utf-8'], ]); }); + it('should update dependencies', async () => { path.join = jest.fn(() => 'file-1'); await autoUpgrade(getContext({ changed: [], added: [], - }), true); + })); // $FlowIgnore updateDependencies is mocked - expect(updateDependencies.mock.calls.length).toBe(1); + expect(checkForMismatch.mock.calls.length).toBe(1); }); }); diff --git a/packages/gluestick/src/commands/autoUpgrade/__tests__/checkForMismatch.test.js b/packages/gluestick/src/commands/autoUpgrade/__tests__/checkForMismatch.test.js index 626fc4dbf..46f3f151b 100644 --- a/packages/gluestick/src/commands/autoUpgrade/__tests__/checkForMismatch.test.js +++ b/packages/gluestick/src/commands/autoUpgrade/__tests__/checkForMismatch.test.js @@ -1,23 +1,51 @@ /* @flow */ -jest.mock('../getSingleEntryFromGenerator.js', () => jest.fn()); + +jest.mock('../getSingleEntryFromGenerator.js', () => (path, name, options) => { + return { + dependencies: { + ...options.gluestickDependencies, + ...options.presetDependencies.dependencies, + }, + devDependencies: options.presetDependencies.devDependencies, + }; +}); + jest.mock('gluestick-generators', () => ({ - parseConfig: jest.fn( - () => ({ - entry: { - template: JSON.stringify({ - dependencies: { - depA: '2.0.0', - depB: '1.0.0', - }, - devDependencies: { - depC: '1.0.0', - }, - }), + parseConfig: v => ({ entry: { template: JSON.stringify(v.entry) } }), +})); + +jest.mock('fs', () => ({ + readFileSync: jest.fn(() => JSON.stringify({ + version: require('../../../../package.json').version, + gsProjectDependencies: { + dependencies: { + depA: '2.0.0', + depB: '1.0.0', }, - }), - ), + devDependencies: { + depC: '1.0.0', + }, + }, + })), })); +jest.mock('node-fetch', () => () => Promise.resolve({ json: () => Promise.resolve({ + versions: { + [require('../../../../package.json').version]: { + gsProjectDependencies: { + dependencies: { + depA: '2.0.0', + depB: '1.0.0', + }, + devDependencies: { + depC: '1.0.0', + }, + }, + }, + }, +}) })); + +const fs = require('fs'); const utils = require('../utils'); const checkForMismatch = require('../checkForMismatch'); @@ -33,9 +61,35 @@ describe('autoUpgrade/checkForMismatch', () => { utils.promptModulesUpdate = orignialPromptModulesUpdate; }); - it('should detect mismatched modules', (done) => { + it('should detect mismatched modules from preset module', () => { + // $FlowIgnore + return checkForMismatch({ + dependencies: { + depA: '1.0.0', + depB: '1.0.0', + }, + }).then(result => { + expect(result).toBeTruthy(); + // $FlowIgnore + expect(utils.promptModulesUpdate.mock.calls[0][0]).toEqual({ + depA: { + required: '2.0.0', + project: '1.0.0', + type: 'dependencies', + }, + depC: { + required: '1.0.0', + project: 'missing', + type: 'devDependencies', + }, + }); + }); + }); + + it('should detect mismatched modules from api request', () => { + fs.readFileSync.mockImplementationOnce(() => { throw new Error(); }); // $FlowIgnore - checkForMismatch({ + return checkForMismatch({ dependencies: { depA: '1.0.0', depB: '1.0.0', @@ -55,7 +109,6 @@ describe('autoUpgrade/checkForMismatch', () => { type: 'devDependencies', }, }); - done(); }); }); }); diff --git a/packages/gluestick/src/commands/autoUpgrade/autoUpgrade.js b/packages/gluestick/src/commands/autoUpgrade/autoUpgrade.js index cff7b778e..cd65d5803 100644 --- a/packages/gluestick/src/commands/autoUpgrade/autoUpgrade.js +++ b/packages/gluestick/src/commands/autoUpgrade/autoUpgrade.js @@ -11,12 +11,14 @@ const updateDependencies = require('./updateDependencies'); const getSingleEntryFromGenerator = require('./getSingleEntryFromGenerator'); const parseConfig = require('gluestick-generators').parseConfig; -module.exports = ({ config, logger }: CLIContext, dev: boolean = false) => { +module.exports = ({ config, logger }: CLIContext) => { const projectPackage: ProjectPackage = require(path.join(process.cwd(), 'package.json')); - config.GSConfig.autoUpgrade.changed.forEach((filePath: string): void => { + const changedFiles: string[] = config.GSConfig.autoUpgrade.changed; + const addedFiles: string[] = config.GSConfig.autoUpgrade.added; + changedFiles.forEach((filePath: string): void => { const currentHash: string = sha1(fs.readFileSync(path.join(process.cwd(), filePath))); const generatorEntry: Object = getSingleEntryFromGenerator( - '../../generator/predefined/new', path.basename(filePath), {}, + '../../generators/predefined/new', path.basename(filePath), {}, ); const entryConfig = parseConfig({ entry: generatorEntry, @@ -25,19 +27,19 @@ module.exports = ({ config, logger }: CLIContext, dev: boolean = false) => { const templateHash: string = sha1(entryConfig.entry.template); if (currentHash !== templateHash) { const absolutePath: string = path.join(process.cwd(), filePath); - logger.success(`${filePath} file is out of date. Updating at path ${absolutePath}...`); + logger.success(`File ${filePath} is out of date. Updating at path ${absolutePath}...`); mkdirp.sync(path.dirname(filePath)); // $FlowIgnore template will be a string fs.writeFileSync(absolutePath, entryConfig.entry.template, 'utf-8'); } }); - config.GSConfig.autoUpgrade.added.forEach((filePath: string): void => { + addedFiles.forEach((filePath: string): void => { if (!fs.existsSync(path.join(process.cwd(), filePath))) { const absolutePath: string = path.join(process.cwd(), filePath); logger.success(`File ${filePath} does not exist. Creating at path ${absolutePath}...`); const generatorEntry: Object = getSingleEntryFromGenerator( - '../../generator/predefined/new', path.basename(filePath), {}, + '../../generators/predefined/new', path.basename(filePath), {}, ); const entryConfig = parseConfig({ entry: generatorEntry, @@ -47,11 +49,13 @@ module.exports = ({ config, logger }: CLIContext, dev: boolean = false) => { fs.writeFileSync(absolutePath, entryConfig.entry.template, 'utf-8'); } }); - // Update dependencies - return checkForMismatch(projectPackage, dev).then((results: UpdateDepsPromptResults): void => { + return checkForMismatch(projectPackage).then((results: UpdateDepsPromptResults): void => { if (results.shouldFix) { updateDependencies(logger, projectPackage, results.mismatchedModules); + logger.success('Project updated'); + } else { + logger.success('Project is already up-to-date'); } }); }; diff --git a/packages/gluestick/src/commands/autoUpgrade/checkForMismatch.js b/packages/gluestick/src/commands/autoUpgrade/checkForMismatch.js index 75e6dee89..c2d31f5a5 100644 --- a/packages/gluestick/src/commands/autoUpgrade/checkForMismatch.js +++ b/packages/gluestick/src/commands/autoUpgrade/checkForMismatch.js @@ -1,11 +1,13 @@ /* @flow */ import type { MismatchedModules, UpdateDepsPromptResults } from '../../types'; +const fs = require('fs'); const path = require('path'); +const fetch = require('node-fetch'); const getSingleEntryFromGenerator = require('./getSingleEntryFromGenerator'); const parseConfig = require('gluestick-generators').parseConfig; const utils = require('./utils'); -const version = require('../../../package.json').version; +const { version, preset = 'default' } = require('../../../package.json'); type ProjectPackage = { dependencies: Object, @@ -35,64 +37,109 @@ type ProjectPackage = { * * @return {Promise} */ -const checkForMismatch = ( - requiredPackage: ProjectPackage, - dev: boolean, -): Promise => { +module.exports = async (projectPackage: ProjectPackage): Promise => { // This is done to keep live reference to mock single function in testing const { isValidVersion, promptModulesUpdate } = utils; - const projectPackage: ProjectPackage = { + const normalizedProjectPackageJson: ProjectPackage = { dependencies: {}, devDependencies: {}, - ...requiredPackage, + ...projectPackage, }; - const pathToPackageGenerator: string = path.join( - require.resolve('gluestick-generators').split('gluestick-generators')[0], - 'gluestick-generators', - 'build/templates/package', + + + const requiredProjectPackageJson: ProjectPackage = { + dependencies: {}, + devDependencies: {}, + }; + + // Check if preset package.json's version is the same as gluestick's version, if so, use + // this preset for dependecies list, otherwise make a request to npm, to get the list. + let presetPackageJson: Object; + try { + // require'ing gluestick-preset-${preset}/package.json will fail, + // if the preset was just installed + presetPackageJson = JSON.parse( + fs.readFileSync( + path.join(process.cwd(), `node_modules/gluestick-preset-${preset}/package.json`), + 'utf-8', + ), + ); + } catch (e) { + presetPackageJson = {}; + } + if (presetPackageJson.version === version) { + requiredProjectPackageJson.dependencies = presetPackageJson + .gsProjectDependencies + .dependencies; + requiredProjectPackageJson.devDependencies = presetPackageJson + .gsProjectDependencies + .devDependencies; + } else { + const api = 'http://registry.npmjs.org'; + try { + const payload = await fetch(`${api}/gluestick-preset-${preset}`) + .then(response => response.json()); + const { gsProjectDependencies } = payload.versions[version]; + requiredProjectPackageJson.dependencies = gsProjectDependencies.dependencies; + requiredProjectPackageJson.devDependencies = gsProjectDependencies.devDependencies; + } catch (error) { + throw new Error(`Error requesting dependency list from npm registry: ${error.message}`); + } + } + + const pathToPackageJsonGenerator: string = require.resolve( + 'gluestick-generators/build/generators/packageJson', ); - const packageGeneratorEntry: Object = getSingleEntryFromGenerator( - pathToPackageGenerator, 'package.json', { gluestickDependencies: { gluestick: version } }, + const packageJsonGeneratorEntry: Object = getSingleEntryFromGenerator( + pathToPackageJsonGenerator, + 'package.json', + { + gluestickDependencies: { gluestick: version }, + presetDependencies: requiredProjectPackageJson, + }, ); - const templatePackage: ProjectPackage = JSON.parse( + const packageJsonTemplate: ProjectPackage = JSON.parse( // $FlowIgnore template at this point will be a string parseConfig({ - entry: packageGeneratorEntry, + entry: packageJsonGeneratorEntry, }, {}).entry.template, ); const mismatchedModules: MismatchedModules = {}; const markMissing = (dep, type) => { mismatchedModules[dep] = { - required: templatePackage[type][dep], - project: projectPackage[type][dep] || 'missing', + required: packageJsonTemplate[type][dep], + project: normalizedProjectPackageJson[type][dep] || 'missing', type, }; }; - Object.keys(templatePackage.dependencies).forEach((dep: string): void => { - if (dev && dep === 'gluestick' && !/\d+\.\d+\.\d+.*/.test(projectPackage.dependencies[dep])) { + + Object.keys(packageJsonTemplate.dependencies).forEach((dep: string): void => { + if (dep === 'gluestick' && !/\d+\.\d+\.\d+.*/.test(normalizedProjectPackageJson.dependencies[dep])) { return; } if ( - !projectPackage.dependencies[dep] || - !isValidVersion(projectPackage.dependencies[dep], templatePackage.dependencies[dep]) + !normalizedProjectPackageJson.dependencies[dep] || + !isValidVersion( + normalizedProjectPackageJson.dependencies[dep], packageJsonTemplate.dependencies[dep], + ) ) { markMissing(dep, 'dependencies'); } }); - Object.keys(templatePackage.devDependencies).forEach((dep: string): void => { + Object.keys(packageJsonTemplate.devDependencies).forEach((dep: string): void => { if ( - !projectPackage.devDependencies[dep] || - !isValidVersion(projectPackage.devDependencies[dep], templatePackage.devDependencies[dep]) + !normalizedProjectPackageJson.devDependencies[dep] || + !isValidVersion( + normalizedProjectPackageJson.devDependencies[dep], packageJsonTemplate.devDependencies[dep], + ) ) { markMissing(dep, 'devDependencies'); } }); - // prompt for updates if we have any, otherwise we are done + // Prompt for updates if we have any, otherwise we are done if (Object.keys(mismatchedModules).length > 0) { return promptModulesUpdate(mismatchedModules); } return Promise.resolve({ shouldFix: false, mismatchedModules: {} }); }; - -module.exports = checkForMismatch; diff --git a/packages/gluestick/src/commands/autoUpgrade/getSingleEntryFromGenerator.js b/packages/gluestick/src/commands/autoUpgrade/getSingleEntryFromGenerator.js index bd0b40755..5af9a45a7 100644 --- a/packages/gluestick/src/commands/autoUpgrade/getSingleEntryFromGenerator.js +++ b/packages/gluestick/src/commands/autoUpgrade/getSingleEntryFromGenerator.js @@ -9,7 +9,7 @@ module.exports = (generatorPath: string, entryFileName: string, options: Object) const compiledGenerator = generator(options); return compiledGenerator.entry ? compiledGenerator.entry - : generator(options).entries.find((entry: Object) => { + : compiledGenerator.entries.find((entry: Object) => { return ( entry.filename === entryFileName || `${entry.filename}${path.extname(entryFileName)}` === entryFileName diff --git a/packages/gluestick/src/commands/autoUpgrade/index.js b/packages/gluestick/src/commands/autoUpgrade/index.js index 9bd14a942..f9bc49832 100644 --- a/packages/gluestick/src/commands/autoUpgrade/index.js +++ b/packages/gluestick/src/commands/autoUpgrade/index.js @@ -1,7 +1,10 @@ /* @flow */ import type { CommandAPI, Logger } from '../../types'; +const path = require('path'); +const { execSync } = require('child_process'); const autoUpgrade = require('./autoUpgrade'); +const { version, preset = 'default' } = require('../../../package.json'); module.exports = async ({ getLogger, getGluestickConfig, getPlugins }: CommandAPI) => { const logger: Logger = getLogger(); @@ -9,12 +12,34 @@ module.exports = async ({ getLogger, getGluestickConfig, getPlugins }: CommandAP logger.clear(); logger.printCommandInfo(); + + const gluestickDependency: string = require( + path.join(process.cwd(), 'package.json'), + ).dependencies.gluestick; + const isDev: boolean = !/\d+\.\d+\.\d+.*/.test(gluestickDependency); + try { + // Check if preset is available, if not install it. + try { + require.resolve(`gluestick-preset-${preset}/package.json`); + } catch (e) { + logger.info(`Preset '${preset}' not found - installing...`); + const packageToInstall = isDev + ? `${gluestickDependency}-preset-${preset}` + : `gluestick-preset-${preset}@${version}`; + execSync(`npm install --save ${packageToInstall}`, { stdio: 'inherit' }); + logger.print(''); + } + // $FlowIgnore no need for compiling webpack config await autoUpgrade({ logger, config: { - GSConfig: getGluestickConfig(logger, getPlugins(logger)), + GSConfig: getGluestickConfig( + logger, + getPlugins(logger), + { hideMissingConfigWarning: true }, + ), }, }); } catch (error) { diff --git a/packages/gluestick/src/config/compileGlueStickConfig.js b/packages/gluestick/src/config/compileGlueStickConfig.js index 34baafb4c..1245d1ce4 100644 --- a/packages/gluestick/src/config/compileGlueStickConfig.js +++ b/packages/gluestick/src/config/compileGlueStickConfig.js @@ -7,24 +7,32 @@ const defaultConfig = require('./defaults/glueStickConfig'); const hooksHelper = require('../renderer/helpers/hooks'); const { requireModule } = require('../utils'); -const getConfigHook = (logger: Logger): Function => { +type Options = { + hideMissingConfigWarning: boolean; +}; + +const getConfigHook = (logger: Logger, { hideMissingConfigWarning }: Options = {}): Function => { try { const configHooks: Function = requireModule( path.join(process.cwd(), defaultConfig.gluestickConfigPath), ); return config => hooksHelper.call(configHooks, config); } catch (e) { - logger.warn('GlueStick config hook was not found. Consider running `gluestick auto-upgrade`.'); + if (!hideMissingConfigWarning) { + logger.warn('GlueStick config hook was not found. Consider running `gluestick auto-upgrade`.'); + } return config => config; } }; -module.exports = (logger: Logger, plugins: ConfigPlugin[]): GSConfig => { +module.exports = ( + logger: Logger, plugins: ConfigPlugin[], { hideMissingConfigWarning }: Options = {}, +): GSConfig => { if (!Array.isArray(plugins)) { throw new Error('Invalid plugins argument'); } - return getConfigHook(logger)( + return getConfigHook(logger, { hideMissingConfigWarning })( plugins .filter((plugin: ConfigPlugin): boolean => !!plugin.postOverwrites.gluestickConfig) // $FlowIgnore filter above ensures `gluestickConfig` won't be undefinfed/null diff --git a/packages/gluestick/src/generator/predefined/new.js b/packages/gluestick/src/generator/predefined/new.js deleted file mode 100644 index f3a4f1ebd..000000000 --- a/packages/gluestick/src/generator/predefined/new.js +++ /dev/null @@ -1,278 +0,0 @@ -/* @flow */ -import type { GeneratorOptions } from '../../types'; - -/* DO NOT MODIFY */ -const createTemplate = module.parent.createTemplate; -/* END OF DO NOT MODIFY */ - -const templateIndex = require('../templates/Index')(createTemplate); -const templateGitignore = require('../templates/gitignore')(createTemplate); -const templateEslintrc = require('../templates/_eslintrc')(createTemplate); -const templateFlowConfig = require('../templates/_flowconfig')(createTemplate); -const templateDockerignore = require('../templates/dockerignore')(createTemplate); -const templateBabelrc = require('../templates/babelrc')(createTemplate); -const templateHomeTest = require('../templates/HomeTest')(createTemplate); -const templateMasterLayoutTest = require('../templates/MasterLayoutTest')(createTemplate); -const templateContainerHomeTest = require('../templates/ContainerHomeTest')(createTemplate); -const templateNoMatchAppTest = require('../templates/NoMatchAppTest')(createTemplate); -const templateEmpty = require('../templates/Empty')(createTemplate); -const templateHome = require('../templates/Home')(createTemplate); -const templateHomeCss = require('../templates/HomeCss.js')(createTemplate); -const templateMasterLayout = require('../templates/MasterLayout')(createTemplate); -const tag = require('../../../package.json').version; -const templateDockerfile = require('../templates/Dockerfile')(createTemplate, tag); -const templateEntryWrapper = require('../templates/EntryWrapper')(createTemplate); -const templateApp = require('../templates/App')(createTemplate); -const templateAppServer = require('../templates/AppServer')(createTemplate); -const templateInitBrowser = require('../templates/InitBrowser')(createTemplate); -const templateReduxMiddleware = require('../templates/ReduxMiddleware')(createTemplate); -const templateRoutes = require('../templates/Routes')(createTemplate); -const templateWebpackAdditions = require('../templates/WebpackAdditions')(createTemplate); -const templateHomeApp = require('../templates/HomeApp')(createTemplate); -const templateNoMatchApp = require('../templates/NoMatchApp')(createTemplate); -const templateReducer = require('../templates/Reducer')(createTemplate); -const templateEntries = require('../templates/entries')(createTemplate); -const templateGluestickPlugins = require('../templates/gluestick.plugins')(createTemplate); -const templateGluestickHooks = require('../templates/gluestick.hooks')(createTemplate); -const templateGluestickConfig = require('../templates/gluestick.config')(createTemplate); -const templateWebpackHooks = require('../templates/webpack.hooks')(createTemplate); -const templateCachingServer = require('../templates/caching.server')(createTemplate); - -const { flowVersion, flowMapper } = require('../constants'); - -module.exports = (options: GeneratorOptions) => { - const entries = [ - { - path: '/', - filename: '.gitignore', - template: templateGitignore, - }, - { - path: '/', - filename: '.eslintrc', - template: templateEslintrc, - }, - { - path: '/', - filename: '.flowconfig', - template: templateFlowConfig, - args: { - appName: options.appName, - version: flowVersion, - mapper: flowMapper, - }, - }, - { - path: '/', - filename: '.dockerignore', - template: templateDockerignore, - }, - { - path: '/', - filename: '.babelrc', - template: templateBabelrc, - }, - { - path: 'src', - filename: 'entries.json', - template: templateEntries, - }, - // Gluestick directory - { - path: 'gluestick', - filename: 'EntryWrapper', - template: templateEntryWrapper, - }, - // Config - { - path: 'src', - filename: 'gluestick.plugins.js', - template: templateGluestickPlugins, - }, - { - path: 'src', - filename: 'gluestick.hooks.js', - template: templateGluestickHooks, - }, - { - path: 'src', - filename: 'gluestick.config.js', - template: templateGluestickConfig, - }, - { - path: 'src', - filename: 'webpack.hooks.js', - template: templateWebpackHooks, - }, - { - path: 'src/config', - filename: '.Dockerfile', - template: templateDockerfile, - }, - { - path: 'src/config', - filename: 'application.js', - template: templateApp, - }, - { - path: 'src/config', - filename: 'application.server.js', - template: templateAppServer, - }, - { - path: 'src/config', - filename: 'init.browser.js', - template: templateInitBrowser, - }, - { - path: 'src/config', - filename: 'redux-middleware.js', - template: templateReduxMiddleware, - }, - { - path: 'src/config', - filename: 'webpack-additions.js', - template: templateWebpackAdditions, - }, - { - path: 'src/config', - filename: 'caching.server.js', - template: templateCachingServer, - }, - // Shared - { - path: 'src/shared/actions', - filename: '.gitkeep', - template: templateEmpty, - }, - { - path: 'src/shared/components', - filename: '.gitkeep', - template: templateEmpty, - }, - { - path: 'src/shared/containers', - filename: '.gitkeep', - template: templateEmpty, - }, - { - path: 'src/shared/reducers', - filename: '.gitkeep', - template: templateEmpty, - }, - // Main app - { - path: 'src/apps/main/assets', - filename: '.gitkeep', - template: templateEmpty, - }, - { - path: 'src/apps/main', - filename: 'routes.js', - template: templateRoutes, - }, - { - path: 'src/apps/main', - filename: 'Index.js', - template: templateIndex, - }, - { - path: 'src/apps/main/components', - filename: 'Home.js', - template: templateHome, - }, - { - path: 'src/apps/main/components', - filename: 'Home.css', - template: templateHomeCss, - }, - { - path: 'src/apps/main/components', - filename: 'MasterLayout.js', - template: templateMasterLayout, - }, - { - path: 'src/apps/main/containers', - filename: 'HomeApp.js', - template: templateHomeApp, - }, - { - path: 'src/apps/main/containers', - filename: 'NoMatchApp.js', - template: templateNoMatchApp, - }, - { - path: 'src/apps/main/actions', - filename: '.gitkeep', - template: templateEmpty, - }, - { - path: 'src/apps/main/reducers', - filename: 'index.js', - template: templateReducer, - }, - { - path: 'src/shared/assets', - filename: '.gitkeep', - template: templateEmpty, - }, - { - path: 'src/shared/reducers', - filename: 'index.js', - template: templateReducer, - }, - { - path: 'src/apps/main/components/__tests__', - filename: 'Home.test.js', - template: templateHomeTest, - }, - { - path: 'src/apps/main/components/__tests__', - filename: 'MasterLayout.test.js', - template: templateMasterLayoutTest, - }, - { - path: 'src/apps/main/containers/__tests__', - filename: 'HomeApp.test.js', - template: templateContainerHomeTest, - }, - { - path: 'src/apps/main/containers/__tests__', - filename: 'NoMatchApp.test.js', - template: templateNoMatchAppTest, - }, - { - path: 'src/apps/main/reducers/__tests__', - filename: '.gitkeep', - template: templateEmpty, - }, - { - path: 'src/apps/main/actions/__tests__', - filename: '.gitkeep', - template: templateEmpty, - }, - { - path: 'src/shared/actions/__tests__', - filename: '.gitkeep', - template: templateEmpty, - }, - { - path: 'src/shared/containers/__tests__', - filename: '.gitkeep', - template: templateEmpty, - }, - { - path: 'src/shared/components/__tests__', - filename: '.gitkeep', - template: templateEmpty, - }, - { - path: 'src/shared/reducers/__tests__', - filename: '.gitkeep', - template: templateEmpty, - }, - ]; - return { - entries: options.skipMain ? entries.filter(o => !o.path.includes('apps/main')) : entries, - }; -}; diff --git a/packages/gluestick/src/generator/templates/ContainerHomeTest.js b/packages/gluestick/src/generator/templates/ContainerHomeTest.js deleted file mode 100644 index 26e8cbe39..000000000 --- a/packages/gluestick/src/generator/templates/ContainerHomeTest.js +++ /dev/null @@ -1,20 +0,0 @@ -/* @flow */ - -import type { CreateTemplate } from '../../types'; - -module.exports = (createTemplate: CreateTemplate) => createTemplate` -/* @flow */ - -import React from "react"; -import { shallow } from "enzyme"; - -import { HomeApp } from "../HomeApp"; - -describe("containers/HomeApp", () => { - it("renders without an issue", () => { - const subject = ; - const wrapper = shallow(subject); - expect(wrapper).toBeDefined(); - }); -}); -`; diff --git a/packages/gluestick/src/generator/templates/HomeTest.js b/packages/gluestick/src/generator/templates/HomeTest.js deleted file mode 100644 index 925022d09..000000000 --- a/packages/gluestick/src/generator/templates/HomeTest.js +++ /dev/null @@ -1,19 +0,0 @@ -/* @flow */ -import type { CreateTemplate } from '../../types'; - -module.exports = (createTemplate: CreateTemplate) => createTemplate` -/* @flow */ - -import React from "react"; -import { shallow } from "enzyme"; - -import Home from "../Home"; - -describe("components/Home", () => { - it("renders without an issue", () => { - const subject = ; - const wrapper = shallow(subject); - expect(wrapper).toBeDefined(); - }); -}); -`; diff --git a/packages/gluestick/src/generator/templates/MasterLayout.js b/packages/gluestick/src/generator/templates/MasterLayout.js deleted file mode 100644 index b17f5533d..000000000 --- a/packages/gluestick/src/generator/templates/MasterLayout.js +++ /dev/null @@ -1,25 +0,0 @@ -/* @flow */ -import type { CreateTemplate } from '../../types'; - -module.exports = (createTemplate: CreateTemplate) => createTemplate` -/* @flow */ - -import React, { Component, PropTypes } from "react"; -import Helmet from "react-helmet"; -import config from "config/application"; - -export default class MasterLayout extends Component { - static propTypes = { - children: PropTypes.any - }; - - render () { - return ( -
- - {this.props.children} -
- ); - } -} -`; diff --git a/packages/gluestick/src/generator/templates/MasterLayoutTest.js b/packages/gluestick/src/generator/templates/MasterLayoutTest.js deleted file mode 100644 index 874475802..000000000 --- a/packages/gluestick/src/generator/templates/MasterLayoutTest.js +++ /dev/null @@ -1,19 +0,0 @@ -/* @flow */ -import type { CreateTemplate } from '../../types'; - -module.exports = (createTemplate: CreateTemplate) => createTemplate` -/* @flow */ - -import React from "react"; -import { shallow } from "enzyme"; - -import MasterLayout from "../MasterLayout"; - -describe("components/MasterLayout", () => { - it("renders without an issue", () => { - const subject = ; - const wrapper = shallow(subject); - expect(wrapper).toBeDefined(); - }); -}); -`; diff --git a/packages/gluestick/src/generator/templates/NoMatchAppTest.js b/packages/gluestick/src/generator/templates/NoMatchAppTest.js deleted file mode 100644 index c7640a895..000000000 --- a/packages/gluestick/src/generator/templates/NoMatchAppTest.js +++ /dev/null @@ -1,19 +0,0 @@ -/* @flow */ -import type { CreateTemplate } from '../../types'; - -module.exports = (createTemplate: CreateTemplate) => createTemplate` -/* @flow */ - -import React from "react"; -import { shallow } from "enzyme"; - -import { NoMatchApp } from "../NoMatchApp"; - -describe("containers/NoMatchApp", () => { - it("renders without an issue", () => { - const subject = ; - const wrapper = shallow(subject); - expect(wrapper).toBeDefined(); - }); -}); -`; diff --git a/packages/gluestick/src/generator/templates/babelrc.js b/packages/gluestick/src/generator/templates/babelrc.js deleted file mode 100644 index 5ac2d803f..000000000 --- a/packages/gluestick/src/generator/templates/babelrc.js +++ /dev/null @@ -1,28 +0,0 @@ -/* @flow */ -import type { CreateTemplate } from '../../types'; - -module.exports = (createTemplate: CreateTemplate) => createTemplate` -{ - "presets": [ - "react", - "es2015", - "stage-0" - ], - "env": { - "development": { - "plugins": [ - ["react-transform", { - "transforms": [{ - "transform": "react-transform-hmr", - "imports": ["react"], - "locals": ["module"] - }, { - "transform": "react-transform-catch-errors", - "imports": ["react", "redbox-react"] - }] - }] - ] - } - } -} -`; diff --git a/packages/gluestick/src/generators/getDataFromPreset.js b/packages/gluestick/src/generators/getDataFromPreset.js new file mode 100644 index 000000000..62cba12d7 --- /dev/null +++ b/packages/gluestick/src/generators/getDataFromPreset.js @@ -0,0 +1,12 @@ +const path = require('path'); + +const getGeneratorPath = (name: string): string => { + const preset: string = `gluestick-preset-${ + require(path.join(process.cwd(), 'package.json')).preset || 'default' + }`; + return `${preset}/build/generators/${name}`; +}; + +module.exports = { + getGeneratorPath, +}; diff --git a/packages/gluestick/src/generators/predefined/app.js b/packages/gluestick/src/generators/predefined/app.js new file mode 100644 index 000000000..c9ab59f44 --- /dev/null +++ b/packages/gluestick/src/generators/predefined/app.js @@ -0,0 +1,24 @@ +/* @flow */ +import type { GeneratorOptions } from '../../types'; + +/* DO NOT MODIFY */ +const createTemplate = module.parent.createTemplate; +/* END OF DO NOT MODIFY */ + +const { + convertToCamelCase, + convertToKebabCase, + convertToPascalCase, + convertToCamelCaseWithPrefix, +} = require('../../utils'); +const { getGeneratorPath } = require('../getDataFromPreset'); + +module.exports = (options: GeneratorOptions) => { + return require(getGeneratorPath('app'))({ + convertToCamelCase, + convertToKebabCase, + convertToPascalCase, + convertToCamelCaseWithPrefix, + createTemplate, + })(options); +}; diff --git a/packages/gluestick/src/generator/predefined/clientEntryInit.js b/packages/gluestick/src/generators/predefined/clientEntryInit.js similarity index 100% rename from packages/gluestick/src/generator/predefined/clientEntryInit.js rename to packages/gluestick/src/generators/predefined/clientEntryInit.js diff --git a/packages/gluestick/src/generators/predefined/component.js b/packages/gluestick/src/generators/predefined/component.js new file mode 100644 index 000000000..1b4becad5 --- /dev/null +++ b/packages/gluestick/src/generators/predefined/component.js @@ -0,0 +1,24 @@ +/* @flow */ +import type { GeneratorOptions } from '../../types'; + +/* DO NOT MODIFY */ +const createTemplate = module.parent.createTemplate; +/* END OF DO NOT MODIFY */ + +const { + convertToCamelCase, + convertToKebabCase, + convertToPascalCase, + convertToCamelCaseWithPrefix, +} = require('../../utils'); +const { getGeneratorPath } = require('../getDataFromPreset'); + +module.exports = (options: GeneratorOptions) => { + return require(getGeneratorPath('component'))({ + convertToCamelCase, + convertToKebabCase, + convertToPascalCase, + convertToCamelCaseWithPrefix, + createTemplate, + })(options); +}; diff --git a/packages/gluestick/src/generators/predefined/container.js b/packages/gluestick/src/generators/predefined/container.js new file mode 100644 index 000000000..6443c3b77 --- /dev/null +++ b/packages/gluestick/src/generators/predefined/container.js @@ -0,0 +1,24 @@ +/* @flow */ +import type { GeneratorOptions } from '../../types'; + +/* DO NOT MODIFY */ +const createTemplate = module.parent.createTemplate; +/* END OF DO NOT MODIFY */ + +const { + convertToCamelCase, + convertToKebabCase, + convertToPascalCase, + convertToCamelCaseWithPrefix, +} = require('../../utils'); +const { getGeneratorPath } = require('../getDataFromPreset'); + +module.exports = (options: GeneratorOptions) => { + return require(getGeneratorPath('container'))({ + convertToCamelCase, + convertToKebabCase, + convertToPascalCase, + convertToCamelCaseWithPrefix, + createTemplate, + })(options); +}; diff --git a/packages/gluestick/src/generator/predefined/generator.js b/packages/gluestick/src/generators/predefined/generator.js similarity index 100% rename from packages/gluestick/src/generator/predefined/generator.js rename to packages/gluestick/src/generators/predefined/generator.js diff --git a/packages/gluestick/src/generators/predefined/new.js b/packages/gluestick/src/generators/predefined/new.js new file mode 100644 index 000000000..480251c4d --- /dev/null +++ b/packages/gluestick/src/generators/predefined/new.js @@ -0,0 +1,123 @@ +/* @flow */ +import type { GeneratorOptions } from '../../types'; + +/* DO NOT MODIFY */ +const createTemplate = module.parent.createTemplate; +/* END OF DO NOT MODIFY */ + +const { + convertToCamelCase, + convertToKebabCase, + convertToPascalCase, + convertToCamelCaseWithPrefix, +} = require('../../utils'); +const { getGeneratorPath } = require('../getDataFromPreset'); + +const templateGitignore = require('../templates/gitignore')(createTemplate); +const templateDockerignore = require('../templates/dockerignore')(createTemplate); +const tag = require('../../../package.json').version; +const templateDockerfile = require('../templates/Dockerfile')(createTemplate, tag); +const templateEntryWrapper = require('../templates/EntryWrapper')(createTemplate); +const templateApp = require('../templates/application')(createTemplate); +const templateAppServer = require('../templates/application.server')(createTemplate); +const templateInitBrowser = require('../templates/init.browser')(createTemplate); +const templateReduxMiddleware = require('../templates/redux-middleware')(createTemplate); +const templateWebpackAdditions = require('../templates/webpack-additions')(createTemplate); +const templateGluestickPlugins = require('../templates/gluestick.plugins')(createTemplate); +const templateGluestickHooks = require('../templates/gluestick.hooks')(createTemplate); +const templateGluestickConfig = require('../templates/gluestick.config')(createTemplate); +const templateWebpackHooks = require('../templates/webpack.hooks')(createTemplate); +const templateCachingServer = require('../templates/caching.server')(createTemplate); + +module.exports = (options: GeneratorOptions) => { + const presetNewGenerator = require(getGeneratorPath('new'))({ + convertToCamelCase, + convertToKebabCase, + convertToPascalCase, + convertToCamelCaseWithPrefix, + createTemplate, + })(options); + + const entries = [ + { + path: '/', + filename: '.gitignore', + template: templateGitignore, + }, + { + path: '/', + filename: '.dockerignore', + template: templateDockerignore, + }, + // Gluestick directory + { + path: 'gluestick', + filename: 'EntryWrapper', + template: templateEntryWrapper, + }, + // Config + { + path: 'src', + filename: 'gluestick.plugins.js', + template: templateGluestickPlugins, + }, + { + path: 'src', + filename: 'gluestick.hooks.js', + template: templateGluestickHooks, + }, + { + path: 'src', + filename: 'gluestick.config.js', + template: templateGluestickConfig, + }, + { + path: 'src', + filename: 'webpack.hooks.js', + template: templateWebpackHooks, + }, + { + path: 'src/config', + filename: '.Dockerfile', + template: templateDockerfile, + }, + { + path: 'src/config', + filename: 'application.js', + template: templateApp, + }, + { + path: 'src/config', + filename: 'application.server.js', + template: templateAppServer, + }, + { + path: 'src/config', + filename: 'init.browser.js', + template: templateInitBrowser, + }, + { + path: 'src/config', + filename: 'redux-middleware.js', + template: templateReduxMiddleware, + }, + { + path: 'src/config', + filename: 'webpack-additions.js', + template: templateWebpackAdditions, + }, + { + path: 'src/config', + filename: 'caching.server.js', + template: templateCachingServer, + }, + ]; + + return { + ...presetNewGenerator, + entries: [ + ...presetNewGenerator.entries, + ...entries, + ], + }; +}; diff --git a/packages/gluestick/src/generators/predefined/reducer.js b/packages/gluestick/src/generators/predefined/reducer.js new file mode 100644 index 000000000..0e96ff6f6 --- /dev/null +++ b/packages/gluestick/src/generators/predefined/reducer.js @@ -0,0 +1,24 @@ +/* @flow */ +import type { GeneratorOptions } from '../../types'; + +/* DO NOT MODIFY */ +const createTemplate = module.parent.createTemplate; +/* END OF DO NOT MODIFY */ + +const { + convertToCamelCase, + convertToKebabCase, + convertToPascalCase, + convertToCamelCaseWithPrefix, +} = require('../../utils'); +const { getGeneratorPath } = require('../getDataFromPreset'); + +module.exports = (options: GeneratorOptions) => { + return require(getGeneratorPath('reducer'))({ + convertToCamelCase, + convertToKebabCase, + convertToPascalCase, + convertToCamelCaseWithPrefix, + createTemplate, + })(options); +}; diff --git a/packages/gluestick/src/generator/predefined/serverEntries.js b/packages/gluestick/src/generators/predefined/serverEntries.js similarity index 100% rename from packages/gluestick/src/generator/predefined/serverEntries.js rename to packages/gluestick/src/generators/predefined/serverEntries.js diff --git a/packages/gluestick/src/generator/templates/500hbs.js b/packages/gluestick/src/generators/templates/500hbs.js similarity index 100% rename from packages/gluestick/src/generator/templates/500hbs.js rename to packages/gluestick/src/generators/templates/500hbs.js diff --git a/packages/gluestick/src/generator/templates/Dockerfile.js b/packages/gluestick/src/generators/templates/Dockerfile.js similarity index 100% rename from packages/gluestick/src/generator/templates/Dockerfile.js rename to packages/gluestick/src/generators/templates/Dockerfile.js diff --git a/packages/gluestick/src/generator/templates/EntryWrapper.js b/packages/gluestick/src/generators/templates/EntryWrapper.js similarity index 100% rename from packages/gluestick/src/generator/templates/EntryWrapper.js rename to packages/gluestick/src/generators/templates/EntryWrapper.js diff --git a/packages/gluestick/src/generator/templates/App.js b/packages/gluestick/src/generators/templates/application.js similarity index 100% rename from packages/gluestick/src/generator/templates/App.js rename to packages/gluestick/src/generators/templates/application.js diff --git a/packages/gluestick/src/generator/templates/AppServer.js b/packages/gluestick/src/generators/templates/application.server.js similarity index 100% rename from packages/gluestick/src/generator/templates/AppServer.js rename to packages/gluestick/src/generators/templates/application.server.js diff --git a/packages/gluestick/src/generator/templates/caching.server.js b/packages/gluestick/src/generators/templates/caching.server.js similarity index 100% rename from packages/gluestick/src/generator/templates/caching.server.js rename to packages/gluestick/src/generators/templates/caching.server.js diff --git a/packages/gluestick/src/generator/templates/dockerignore.js b/packages/gluestick/src/generators/templates/dockerignore.js similarity index 100% rename from packages/gluestick/src/generator/templates/dockerignore.js rename to packages/gluestick/src/generators/templates/dockerignore.js diff --git a/packages/gluestick/src/generator/templates/gitignore.js b/packages/gluestick/src/generators/templates/gitignore.js similarity index 100% rename from packages/gluestick/src/generator/templates/gitignore.js rename to packages/gluestick/src/generators/templates/gitignore.js diff --git a/packages/gluestick/src/generator/templates/gluestick.config.js b/packages/gluestick/src/generators/templates/gluestick.config.js similarity index 100% rename from packages/gluestick/src/generator/templates/gluestick.config.js rename to packages/gluestick/src/generators/templates/gluestick.config.js diff --git a/packages/gluestick/src/generator/templates/gluestick.hooks.js b/packages/gluestick/src/generators/templates/gluestick.hooks.js similarity index 100% rename from packages/gluestick/src/generator/templates/gluestick.hooks.js rename to packages/gluestick/src/generators/templates/gluestick.hooks.js diff --git a/packages/gluestick/src/generator/templates/gluestick.plugins.js b/packages/gluestick/src/generators/templates/gluestick.plugins.js similarity index 100% rename from packages/gluestick/src/generator/templates/gluestick.plugins.js rename to packages/gluestick/src/generators/templates/gluestick.plugins.js diff --git a/packages/gluestick/src/generator/templates/InitBrowser.js b/packages/gluestick/src/generators/templates/init.browser.js similarity index 100% rename from packages/gluestick/src/generator/templates/InitBrowser.js rename to packages/gluestick/src/generators/templates/init.browser.js diff --git a/packages/gluestick/src/generator/templates/ReduxMiddleware.js b/packages/gluestick/src/generators/templates/redux-middleware.js similarity index 100% rename from packages/gluestick/src/generator/templates/ReduxMiddleware.js rename to packages/gluestick/src/generators/templates/redux-middleware.js diff --git a/packages/gluestick/src/generator/templates/WebpackAdditions.js b/packages/gluestick/src/generators/templates/webpack-additions.js similarity index 100% rename from packages/gluestick/src/generator/templates/WebpackAdditions.js rename to packages/gluestick/src/generators/templates/webpack-additions.js diff --git a/packages/gluestick/src/generator/templates/webpack.hooks.js b/packages/gluestick/src/generators/templates/webpack.hooks.js similarity index 100% rename from packages/gluestick/src/generator/templates/webpack.hooks.js rename to packages/gluestick/src/generators/templates/webpack.hooks.js