From d20e1b304314b0384933fbfc1f58131bbf561097 Mon Sep 17 00:00:00 2001 From: Keraito Date: Fri, 14 Sep 2018 02:18:22 +0200 Subject: [PATCH 01/10] Add CLI flag to choose SB framework to install --- lib/cli/bin/generate.js | 1 + lib/cli/lib/detect.js | 2 +- lib/cli/lib/initiate.js | 29 +++++++++++++++++++++++------ lib/cli/lib/project_types.js | 14 +++++++++++++- 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/lib/cli/bin/generate.js b/lib/cli/bin/generate.js index 7040af903a21..0d9c58d1dc9e 100644 --- a/lib/cli/bin/generate.js +++ b/lib/cli/bin/generate.js @@ -24,6 +24,7 @@ program .option('-N --use-npm', 'Use npm to install deps') .option('-p --parser ', 'jscodeshift parser') .option('-h --html', 'Add storybook for HTML') + .option('-t --type ', 'Add Storybook for a specific project type') .action(options => initiate(options, pkg)); program diff --git a/lib/cli/lib/detect.js b/lib/cli/lib/detect.js index 32c490c97bef..94a3e37b0593 100644 --- a/lib/cli/lib/detect.js +++ b/lib/cli/lib/detect.js @@ -101,7 +101,7 @@ function detectFramework(dependencies) { return false; } -function isStorybookInstalled(dependencies, force) { +export function isStorybookInstalled(dependencies, force) { if (!dependencies) { return false; } diff --git a/lib/cli/lib/initiate.js b/lib/cli/lib/initiate.js index 5f019c21a96f..a8947bbca0e8 100644 --- a/lib/cli/lib/initiate.js +++ b/lib/cli/lib/initiate.js @@ -1,9 +1,9 @@ import updateNotifier from 'update-notifier'; import chalk from 'chalk'; -import detect from './detect'; +import detect, { isStorybookInstalled } from './detect'; import hasYarn from './has_yarn'; -import types from './project_types'; -import { commandLog, codeLog, paddedLog, installDeps } from './helpers'; +import types, { installableProjectTypes } from './project_types'; +import { commandLog, codeLog, paddedLog, installDeps, getPackageJson } from './helpers'; import angularGenerator from '../generators/ANGULAR'; import meteorGenerator from '../generators/METEOR'; import reactGenerator from '../generators/REACT'; @@ -41,10 +41,27 @@ export default function(options, pkg) { }).notify(); let projectType; + const projectTypeProvided = options.type; + const infoText = projectTypeProvided + ? 'Installing Storybook for user specified project type' + : 'Detecting project type'; + const done = commandLog(infoText); - const done = commandLog('Detecting project type'); try { - projectType = detect(options); + if (projectTypeProvided) { + if (installableProjectTypes.includes(options.type)) { + const storybookInstalled = isStorybookInstalled(getPackageJson(), options.force); + projectType = storybookInstalled ? types.ALREADY_HAS_STORYBOOK : options.type.toUpperCase(); + } else { + done(`The provided project type was not recognized by Storybook.`); + logger.log(`\nThe project types currently supported by Storybook are:\n`); + installableProjectTypes.sort().forEach(framework => paddedLog(`- ${framework}`)); + logger.log(); + process.exit(1); + } + } else { + projectType = detect(options); + } } catch (ex) { done(ex.message); process.exit(1); @@ -73,7 +90,7 @@ export default function(options, pkg) { logger.log(); paddedLog('There seems to be a storybook already available in this project.'); paddedLog('Apply following command to force:\n'); - codeLog(['storybook init -f']); + codeLog(['storybook init [options] -f']); // Add a new line for the clear visibility. logger.log(); diff --git a/lib/cli/lib/project_types.js b/lib/cli/lib/project_types.js index 7e07c230f989..eb931c91e614 100644 --- a/lib/cli/lib/project_types.js +++ b/lib/cli/lib/project_types.js @@ -1,4 +1,4 @@ -export default { +const projectTypes = { UNDETECTED: 'UNDETECTED', REACT_SCRIPTS: 'REACT_SCRIPTS', METEOR: 'METEOR', @@ -18,3 +18,15 @@ export default { HTML: 'HTML', RIOT: 'RIOT', }; + +export default projectTypes; + +const notInstallableProjectTypes = [ + projectTypes.UNDETECTED, + projectTypes.ALREADY_HAS_STORYBOOK, + projectTypes.UPDATE_PACKAGE_ORGANIZATIONS, +]; + +export const installableProjectTypes = Object.values(projectTypes) + .filter(type => !notInstallableProjectTypes.includes(type)) + .map(type => type.toLowerCase()); From d60900f53712af243eb557f1c45ea5c5ed26ec3c Mon Sep 17 00:00:00 2001 From: Keraito Date: Fri, 14 Sep 2018 02:19:14 +0200 Subject: [PATCH 02/10] Remove manual HTML CLI flag --- lib/cli/bin/generate.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/cli/bin/generate.js b/lib/cli/bin/generate.js index 0d9c58d1dc9e..de71ba515414 100644 --- a/lib/cli/bin/generate.js +++ b/lib/cli/bin/generate.js @@ -23,7 +23,6 @@ program .option('-s --skip-install', 'Skip installing deps') .option('-N --use-npm', 'Use npm to install deps') .option('-p --parser ', 'jscodeshift parser') - .option('-h --html', 'Add storybook for HTML') .option('-t --type ', 'Add Storybook for a specific project type') .action(options => initiate(options, pkg)); From 332cbbf1ab373819fc08f5836b1e0949623a887c Mon Sep 17 00:00:00 2001 From: Keraito Date: Fri, 14 Sep 2018 12:02:39 +0200 Subject: [PATCH 03/10] Update command for html sb --- lib/cli/lib/initiate.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cli/lib/initiate.js b/lib/cli/lib/initiate.js index a8947bbca0e8..40eca21c712f 100644 --- a/lib/cli/lib/initiate.js +++ b/lib/cli/lib/initiate.js @@ -193,7 +193,7 @@ export default function(options, pkg) { "Please make sure you are running the `storybook init` command in your project's root directory." ); paddedLog( - 'You can also install storybook for plain HTML snippets with `storybook init --html` or follow some of the slow start guides: https://storybook.js.org/basics/slow-start-guide/' + 'You can also install storybook for plain HTML snippets with `storybook init --type html` or follow some of the slow start guides: https://storybook.js.org/basics/slow-start-guide/' ); // Add a new line for the clear visibility. From 355dae21d281dec810385f780789855dd087b743 Mon Sep 17 00:00:00 2001 From: Keraito Date: Fri, 14 Sep 2018 17:29:51 +0200 Subject: [PATCH 04/10] Prompt type inquirer when no project type is detected --- lib/cli/lib/initiate.js | 109 ++++++++++++++++++++++++++-------------- lib/cli/package.json | 1 + 2 files changed, 71 insertions(+), 39 deletions(-) diff --git a/lib/cli/lib/initiate.js b/lib/cli/lib/initiate.js index 40eca21c712f..a09bc9b294e1 100644 --- a/lib/cli/lib/initiate.js +++ b/lib/cli/lib/initiate.js @@ -1,5 +1,6 @@ import updateNotifier from 'update-notifier'; import chalk from 'chalk'; +import inquirer from 'inquirer'; import detect, { isStorybookInstalled } from './detect'; import hasYarn from './has_yarn'; import types, { installableProjectTypes } from './project_types'; @@ -22,10 +23,7 @@ import riotGenerator from '../generators/RIOT'; const logger = console; -export default function(options, pkg) { - const welcomeMessage = 'storybook init - the simplest way to add a storybook to your project.'; - logger.log(chalk.inverse(`\n ${welcomeMessage} \n`)); - +const installStorybook = (projectType, options) => { const useYarn = Boolean(options.useNpm !== true) && hasYarn(); const npmOptions = { @@ -34,40 +32,6 @@ export default function(options, pkg) { const runStorybookCommand = 'storybook start'; - // Update notify code. - updateNotifier({ - pkg, - updateCheckInterval: 1000 * 60 * 60, // every hour (we could increase this later on.) - }).notify(); - - let projectType; - const projectTypeProvided = options.type; - const infoText = projectTypeProvided - ? 'Installing Storybook for user specified project type' - : 'Detecting project type'; - const done = commandLog(infoText); - - try { - if (projectTypeProvided) { - if (installableProjectTypes.includes(options.type)) { - const storybookInstalled = isStorybookInstalled(getPackageJson(), options.force); - projectType = storybookInstalled ? types.ALREADY_HAS_STORYBOOK : options.type.toUpperCase(); - } else { - done(`The provided project type was not recognized by Storybook.`); - logger.log(`\nThe project types currently supported by Storybook are:\n`); - installableProjectTypes.sort().forEach(framework => paddedLog(`- ${framework}`)); - logger.log(); - process.exit(1); - } - } else { - projectType = detect(options); - } - } catch (ex) { - done(ex.message); - process.exit(1); - } - done(); - const end = () => { if (!options.skipInstall) { installDeps(npmOptions); @@ -198,7 +162,8 @@ export default function(options, pkg) { // Add a new line for the clear visibility. logger.log(); - return Promise.resolve(); + // eslint-disable-next-line no-use-before-define + return projectTypeInquirer(options); } }; @@ -206,4 +171,70 @@ export default function(options, pkg) { logger.error(`\n ${chalk.red(ex.stack)}`); process.exit(1); }); +}; + +const projectTypeInquirer = options => + inquirer + .prompt([ + { + type: 'confirm', + name: 'manual', + message: 'Do you want to manually choose a Storybook project type to install?', + default: false, + }, + ]) + .then( + manualAnswer => + manualAnswer.manual && + inquirer + .prompt([ + { + type: 'list', + name: 'manualFramework', + message: 'Please choose a project type from the following list:', + choices: installableProjectTypes.map(type => type.toUpperCase()), + }, + ]) + .then(frameworkAnswer => installStorybook(frameworkAnswer.manualFramework, options)) + ); + +export default function(options, pkg) { + const welcomeMessage = 'storybook init - the simplest way to add a storybook to your project.'; + logger.log(chalk.inverse(`\n ${welcomeMessage} \n`)); + + // Update notify code. + updateNotifier({ + pkg, + updateCheckInterval: 1000 * 60 * 60, // every hour (we could increase this later on.) + }).notify(); + + let projectType; + const projectTypeProvided = options.type; + const infoText = projectTypeProvided + ? 'Installing Storybook for user specified project type' + : 'Detecting project type'; + const done = commandLog(infoText); + + try { + if (projectTypeProvided) { + if (installableProjectTypes.includes(options.type)) { + const storybookInstalled = isStorybookInstalled(getPackageJson(), options.force); + projectType = storybookInstalled ? types.ALREADY_HAS_STORYBOOK : options.type.toUpperCase(); + } else { + done(`The provided project type was not recognized by Storybook.`); + logger.log(`\nThe project types currently supported by Storybook are:\n`); + installableProjectTypes.sort().forEach(framework => paddedLog(`- ${framework}`)); + logger.log(); + process.exit(1); + } + } else { + projectType = detect(options); + } + } catch (ex) { + done(ex.message); + process.exit(1); + } + done(); + + return installStorybook(projectType, options); } diff --git a/lib/cli/package.json b/lib/cli/package.json index 5ea42997112d..0f3294b02c49 100644 --- a/lib/cli/package.json +++ b/lib/cli/package.json @@ -36,6 +36,7 @@ "child-process-promise": "^2.2.1", "commander": "^2.17.0", "cross-spawn": "^6.0.5", + "inquirer": "^6.2.0", "jscodeshift": "^0.5.1", "json5": "^2.0.1", "merge-dirs": "^0.2.1", From a9ddc7e4c2e33b65acf5cfb435aaad95b20eecf7 Mon Sep 17 00:00:00 2001 From: Keraito Date: Fri, 14 Sep 2018 17:32:52 +0200 Subject: [PATCH 05/10] Make manual inquirer check more descripti e --- lib/cli/lib/initiate.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/cli/lib/initiate.js b/lib/cli/lib/initiate.js index a09bc9b294e1..fa708d6251a8 100644 --- a/lib/cli/lib/initiate.js +++ b/lib/cli/lib/initiate.js @@ -183,9 +183,8 @@ const projectTypeInquirer = options => default: false, }, ]) - .then( - manualAnswer => - manualAnswer.manual && + .then(manualAnswer => { + if (manualAnswer.manual) { inquirer .prompt([ { @@ -195,8 +194,9 @@ const projectTypeInquirer = options => choices: installableProjectTypes.map(type => type.toUpperCase()), }, ]) - .then(frameworkAnswer => installStorybook(frameworkAnswer.manualFramework, options)) - ); + .then(frameworkAnswer => installStorybook(frameworkAnswer.manualFramework, options)); + } + }); export default function(options, pkg) { const welcomeMessage = 'storybook init - the simplest way to add a storybook to your project.'; From 2506564c56422eb3569a32a514a51575db061fd2 Mon Sep 17 00:00:00 2001 From: Keraito Date: Fri, 14 Sep 2018 21:02:10 +0200 Subject: [PATCH 06/10] Rewrite inquire promises for comprehensibility --- lib/cli/lib/initiate.js | 43 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/lib/cli/lib/initiate.js b/lib/cli/lib/initiate.js index fa708d6251a8..caa713186462 100644 --- a/lib/cli/lib/initiate.js +++ b/lib/cli/lib/initiate.js @@ -173,30 +173,29 @@ const installStorybook = (projectType, options) => { }); }; -const projectTypeInquirer = options => - inquirer - .prompt([ +const projectTypeInquirer = async options => { + const manualAnswer = await inquirer.prompt([ + { + type: 'confirm', + name: 'manual', + message: 'Do you want to manually choose a Storybook project type to install?', + default: false, + }, + ]); + + if (manualAnswer.manual) { + const frameworkAnswer = await inquirer.prompt([ { - type: 'confirm', - name: 'manual', - message: 'Do you want to manually choose a Storybook project type to install?', - default: false, + type: 'list', + name: 'manualFramework', + message: 'Please choose a project type from the following list:', + choices: installableProjectTypes.map(type => type.toUpperCase()), }, - ]) - .then(manualAnswer => { - if (manualAnswer.manual) { - inquirer - .prompt([ - { - type: 'list', - name: 'manualFramework', - message: 'Please choose a project type from the following list:', - choices: installableProjectTypes.map(type => type.toUpperCase()), - }, - ]) - .then(frameworkAnswer => installStorybook(frameworkAnswer.manualFramework, options)); - } - }); + ]); + return installStorybook(frameworkAnswer.manualFramework, options); + } + return Promise.resolve(); +}; export default function(options, pkg) { const welcomeMessage = 'storybook init - the simplest way to add a storybook to your project.'; From c018d98e8f51c0addc9b852b00403289c89659cc Mon Sep 17 00:00:00 2001 From: Keraito Date: Thu, 20 Sep 2018 11:00:24 +0200 Subject: [PATCH 07/10] Change Undetected project feedback --- lib/cli/lib/initiate.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/cli/lib/initiate.js b/lib/cli/lib/initiate.js index caa713186462..96cea536e4ec 100644 --- a/lib/cli/lib/initiate.js +++ b/lib/cli/lib/initiate.js @@ -154,10 +154,7 @@ const installStorybook = (projectType, options) => { default: paddedLog(`We couldn't detect your project type. (code: ${projectType})`); paddedLog( - "Please make sure you are running the `storybook init` command in your project's root directory." - ); - paddedLog( - 'You can also install storybook for plain HTML snippets with `storybook init --type html` or follow some of the slow start guides: https://storybook.js.org/basics/slow-start-guide/' + 'You can specify a project type explicitly via `storybook init --type ` or follow some of the slow start guides: https://storybook.js.org/basics/slow-start-guide/' ); // Add a new line for the clear visibility. From 2f5a249727392a3639c8d5263814ef64ba522d91 Mon Sep 17 00:00:00 2001 From: Keraito Date: Thu, 20 Sep 2018 11:01:13 +0200 Subject: [PATCH 08/10] Extract supported frameworks and test --- lib/cli/lib/detect.js | 11 +---------- lib/cli/lib/project_types.js | 10 ++++++++++ lib/cli/lib/project_types.test.js | 9 +++++++++ 3 files changed, 20 insertions(+), 10 deletions(-) create mode 100644 lib/cli/lib/project_types.test.js diff --git a/lib/cli/lib/detect.js b/lib/cli/lib/detect.js index 94a3e37b0593..832db5b28ab8 100644 --- a/lib/cli/lib/detect.js +++ b/lib/cli/lib/detect.js @@ -1,6 +1,6 @@ import path from 'path'; import fs from 'fs'; -import types from './project_types'; +import types, { supportedFrameworks } from './project_types'; import { getBowerJson, getPackageJson } from './helpers'; function detectFramework(dependencies) { @@ -107,15 +107,6 @@ export function isStorybookInstalled(dependencies, force) { } if (!force && dependencies.devDependencies) { - const supportedFrameworks = [ - 'react', - 'react-native', - 'vue', - 'angular', - 'polymer', - 'mithril', - 'riot', - ]; if ( supportedFrameworks.reduce( (storybookPresent, framework) => diff --git a/lib/cli/lib/project_types.js b/lib/cli/lib/project_types.js index eb931c91e614..52d40a7e905c 100644 --- a/lib/cli/lib/project_types.js +++ b/lib/cli/lib/project_types.js @@ -21,6 +21,16 @@ const projectTypes = { export default projectTypes; +export const supportedFrameworks = [ + 'react', + 'react-native', + 'vue', + 'angular', + 'polymer', + 'mithril', + 'riot', +]; + const notInstallableProjectTypes = [ projectTypes.UNDETECTED, projectTypes.ALREADY_HAS_STORYBOOK, diff --git a/lib/cli/lib/project_types.test.js b/lib/cli/lib/project_types.test.js new file mode 100644 index 000000000000..b69eb1a18c43 --- /dev/null +++ b/lib/cli/lib/project_types.test.js @@ -0,0 +1,9 @@ +import { installableProjectTypes, supportedFrameworks } from './project_types'; + +describe('installableProjectTypes should have an entry for the supported framework', () => { + supportedFrameworks.forEach(framework => { + it(`${framework}`, () => { + expect(installableProjectTypes.includes(framework.replace(/-/g, '_'))).toBe(true); + }); + }); +}); From 79d316ae79d16dc4136d6f598cdea45af8aca505 Mon Sep 17 00:00:00 2001 From: Keraito Date: Thu, 20 Sep 2018 11:02:28 +0200 Subject: [PATCH 09/10] Test installed storybook checker --- lib/cli/lib/detect.test.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 lib/cli/lib/detect.test.js diff --git a/lib/cli/lib/detect.test.js b/lib/cli/lib/detect.test.js new file mode 100644 index 000000000000..b2cf308d2021 --- /dev/null +++ b/lib/cli/lib/detect.test.js @@ -0,0 +1,27 @@ +import { isStorybookInstalled } from './detect'; +import { supportedFrameworks } from './project_types'; + +describe('isStorybookInstalled should return', () => { + it('false if empty devDependency', () => { + expect(isStorybookInstalled({ devDependencies: {} }, false)).toBe(false); + }); + it('false if no devDependency', () => { + expect(isStorybookInstalled({}, false)).toBe(false); + }); + + supportedFrameworks.forEach(framework => { + it(`true if devDependencies has ${framework} Storybook version`, () => { + const devDependencies = {}; + devDependencies[`@storybook/${framework}`] = '4.0.0-alpha.21'; + expect(isStorybookInstalled({ devDependencies }, false)).toBeTruthy(); + }); + }); + + it('true if forced flag', () => { + expect( + isStorybookInstalled({ + devDependencies: { 'storybook/react': '4.0.0-alpha.21' }, + }) + ).toBe(false); + }); +}); From cba68c4b9c6a12030cf4cd542466c8cabe41945c Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Sat, 13 Oct 2018 15:08:13 +0800 Subject: [PATCH 10/10] Add missing project types --- lib/cli/lib/project_types.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/cli/lib/project_types.js b/lib/cli/lib/project_types.js index 4326eb96d1d4..a4dc556cef74 100644 --- a/lib/cli/lib/project_types.js +++ b/lib/cli/lib/project_types.js @@ -30,6 +30,9 @@ export const supportedFrameworks = [ 'polymer', 'mithril', 'riot', + 'ember', + 'marko', + 'meteor', ]; const notInstallableProjectTypes = [