Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prompt to force initialization when storybook folder is detected #22392

Merged
merged 5 commits into from
May 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
34 changes: 2 additions & 32 deletions code/lib/cli/src/detect.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as fs from 'fs';
import { logger } from '@storybook/node-logger';
import { getBowerJson } from './helpers';
import { detect, detectFrameworkPreset, detectLanguage, isStorybookInstalled } from './detect';
import { ProjectType, SUPPORTED_RENDERERS, SupportedLanguage } from './project_types';
import { detect, detectFrameworkPreset, detectLanguage } from './detect';
import { ProjectType, SupportedLanguage } from './project_types';
import type { PackageJsonWithMaybeDeps } from './js-package-manager';

jest.mock('./helpers', () => ({
Expand Down Expand Up @@ -346,36 +346,6 @@ describe('Detect', () => {
expect(detectLanguage()).toBe(SupportedLanguage.JAVASCRIPT);
});

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);
});

SUPPORTED_RENDERERS.forEach((framework) => {
it(`true if devDependencies has ${framework} Storybook version`, () => {
const devDependencies = {
[`@storybook/${framework}`]: '4.0.0-alpha.21',
};
expect(isStorybookInstalled({ devDependencies }, false)).toBeTruthy();
});
});

it('false if forced flag', () => {
expect(
isStorybookInstalled(
{
devDependencies: { '@storybook/react': '4.0.0-alpha.21' },
},
true
)
).toBe(false);
});
});

describe('detectFrameworkPreset should return', () => {
afterEach(() => {
jest.clearAllMocks();
Expand Down
31 changes: 6 additions & 25 deletions code/lib/cli/src/detect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,16 @@ import semver from 'semver';
import { logger } from '@storybook/node-logger';

import { pathExistsSync } from 'fs-extra';
import { join } from 'path';
import { join, resolve } from 'path';
import type { TemplateConfiguration, TemplateMatcher } from './project_types';
import {
ProjectType,
supportedTemplates,
SUPPORTED_RENDERERS,
SupportedLanguage,
unsupportedTemplate,
CoreBuilder,
} from './project_types';
import { getBowerJson, isNxProject, paddedLog } from './helpers';
import { commandLog, getBowerJson, isNxProject } from './helpers';
import type { JsPackageManager, PackageJson, PackageJsonWithMaybeDeps } from './js-package-manager';
import { detectWebpack } from './detect-webpack';

Expand Down Expand Up @@ -112,12 +111,12 @@ export function detectFrameworkPreset(
export function detectBuilder(packageManager: JsPackageManager, projectType: ProjectType) {
const viteConfig = findUp.sync(viteConfigFiles);
if (viteConfig) {
paddedLog('Detected Vite project. Setting builder to Vite');
commandLog('Detected Vite project. Setting builder to Vite')();
return CoreBuilder.Vite;
}

if (detectWebpack(packageManager)) {
paddedLog('Detected webpack project. Setting builder to webpack');
commandLog('Detected webpack project. Setting builder to webpack')();
return CoreBuilder.Webpack5;
}

Expand All @@ -134,26 +133,8 @@ export function detectBuilder(packageManager: JsPackageManager, projectType: Pro
}
}

export function isStorybookInstalled(
dependencies: Pick<PackageJson, 'devDependencies'> | false,
force?: boolean
) {
if (!dependencies) {
return false;
}

if (!force && dependencies.devDependencies) {
if (
SUPPORTED_RENDERERS.reduce(
(storybookPresent, framework) =>
storybookPresent || !!dependencies.devDependencies[`@storybook/${framework}`],
false
)
) {
return true;
}
}
return false;
export function isStorybookInstantiated(configDir = resolve(process.cwd(), '.storybook')) {
return fs.existsSync(configDir);
}

export function detectPnp() {
Expand Down
83 changes: 49 additions & 34 deletions code/lib/cli/src/initiate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ import { telemetry } from '@storybook/telemetry';
import { withTelemetry } from '@storybook/core-server';

import { installableProjectTypes, ProjectType } from './project_types';
import { detect, isStorybookInstalled, detectLanguage, detectBuilder, detectPnp } from './detect';
import {
detect,
isStorybookInstantiated,
detectLanguage,
detectBuilder,
detectPnp,
} from './detect';
import { commandLog, codeLog, paddedLog } from './helpers';
import angularGenerator from './generators/ANGULAR';
import aureliaGenerator from './generators/AURELIA';
Expand Down Expand Up @@ -77,118 +83,118 @@ const installStorybook = async <Project extends ProjectType>(

case ProjectType.REACT:
return reactGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "React" app\n')
commandLog('Adding Storybook support to your "React" app')
);

case ProjectType.REACT_NATIVE: {
return reactNativeGenerator(packageManager, npmOptions).then(
commandLog('Adding Storybook support to your "React Native" app\n')
commandLog('Adding Storybook support to your "React Native" app')
);
}

case ProjectType.QWIK: {
return qwikGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "Qwik" app\n')
commandLog('Adding Storybook support to your "Qwik" app')
);
}

case ProjectType.WEBPACK_REACT:
return webpackReactGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "Webpack React" app\n')
commandLog('Adding Storybook support to your "Webpack React" app')
);

case ProjectType.REACT_PROJECT:
return reactGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "React" library\n')
commandLog('Adding Storybook support to your "React" library')
);

case ProjectType.NEXTJS:
return nextjsGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "Next" app\n')
commandLog('Adding Storybook support to your "Next" app')
);

case ProjectType.SFC_VUE:
return sfcVueGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "Single File Components Vue" app\n')
commandLog('Adding Storybook support to your "Single File Components Vue" app')
);

case ProjectType.VUE:
return vueGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "Vue" app\n')
commandLog('Adding Storybook support to your "Vue" app')
);

case ProjectType.VUE3:
return vue3Generator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "Vue 3" app\n')
commandLog('Adding Storybook support to your "Vue 3" app')
);

case ProjectType.ANGULAR:
commandLog('Adding Storybook support to your "Angular" app\n');
commandLog('Adding Storybook support to your "Angular" app');
return angularGenerator(packageManager, npmOptions, generatorOptions, options);

case ProjectType.EMBER:
return emberGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "Ember" app\n')
commandLog('Adding Storybook support to your "Ember" app')
);

case ProjectType.MITHRIL:
return mithrilGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "Mithril" app\n')
commandLog('Adding Storybook support to your "Mithril" app')
);

case ProjectType.MARIONETTE:
return marionetteGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "Marionette.js" app\n')
commandLog('Adding Storybook support to your "Marionette.js" app')
);

case ProjectType.MARKO:
return markoGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "Marko" app\n')
commandLog('Adding Storybook support to your "Marko" app')
);

case ProjectType.HTML:
return htmlGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "HTML" app\n')
commandLog('Adding Storybook support to your "HTML" app')
);

case ProjectType.WEB_COMPONENTS:
return webComponentsGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "web components" app\n')
commandLog('Adding Storybook support to your "web components" app')
);

case ProjectType.RIOT:
return riotGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "riot.js" app\n')
commandLog('Adding Storybook support to your "riot.js" app')
);

case ProjectType.PREACT:
return preactGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "Preact" app\n')
commandLog('Adding Storybook support to your "Preact" app')
);

case ProjectType.SVELTE:
return svelteGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "Svelte" app\n')
commandLog('Adding Storybook support to your "Svelte" app')
);

case ProjectType.SVELTEKIT:
return svelteKitGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "SvelteKit" app\n')
commandLog('Adding Storybook support to your "SvelteKit" app')
);

case ProjectType.RAX:
return raxGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "Rax" app\n')
commandLog('Adding Storybook support to your "Rax" app')
);

case ProjectType.AURELIA:
return aureliaGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "Aurelia" app\n')
commandLog('Adding Storybook support to your "Aurelia" app')
);

case ProjectType.SERVER:
return serverGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "Server" app\n')
commandLog('Adding Storybook support to your "Server" app')
);

case ProjectType.NX /* NX */:
Expand All @@ -200,7 +206,7 @@ const installStorybook = async <Project extends ProjectType>(

case ProjectType.SOLID:
return solidGenerator(packageManager, npmOptions, generatorOptions).then(
commandLog('Adding Storybook support to your "SolidJS" app\n')
commandLog('Adding Storybook support to your "SolidJS" app')
);

case ProjectType.UNSUPPORTED:
Expand Down Expand Up @@ -313,22 +319,31 @@ async function doInitiate(options: CommandOptions, pkg: PackageJson): Promise<vo
}
done();

const storybookInstalled = isStorybookInstalled(packageJson, options.force);
const storybookInstantiated = isStorybookInstantiated();

if (storybookInstalled && projectType !== ProjectType.ANGULAR) {
if (storybookInstantiated && projectType !== ProjectType.ANGULAR) {
logger.log();
paddedLog('There seems to be a Storybook already available in this project.');
paddedLog('Apply following command to force:\n');
codeLog(['sb init [options] -f']);

// Add a new line for the clear visibility.
const { force } = await prompts([
{
type: 'confirm',
name: 'force',
message:
'We found a .storybook config directory in your project. Therefore we assume that Storybook is already instantiated for your project. Do you still want to continue and force the initialization?',
},
]);
logger.log();
throw new HandledError(`Angular project already installed`);

if (force) {
// eslint-disable-next-line no-param-reassign
options.force = true;
} else {
process.exit(0);
}
valentinpalkovic marked this conversation as resolved.
Show resolved Hide resolved
}

const installResult = await installStorybook(projectType as ProjectType, packageManager, options);

if (!options.skipInstall && !storybookInstalled) {
if (!options.skipInstall) {
await packageManager.installDependencies();
}

Expand Down