-
-
Notifications
You must be signed in to change notification settings - Fork 9.2k
/
initiate.ts
311 lines (265 loc) · 11.4 KB
/
initiate.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
import { UpdateNotifier, IPackage } from 'update-notifier';
import chalk from 'chalk';
import inquirer from 'inquirer';
import { detect, isStorybookInstalled, detectLanguage } from './detect';
import {
installableProjectTypes,
ProjectType,
StoryFormat,
SupportedLanguage,
} from './project_types';
import { commandLog, codeLog, paddedLog } from './helpers';
import angularGenerator from './generators/ANGULAR';
import aureliaGenerator from './generators/AURELIA';
import emberGenerator from './generators/EMBER';
import meteorGenerator from './generators/METEOR';
import reactGenerator from './generators/REACT';
import reactNativeGenerator from './generators/REACT_NATIVE';
import reactScriptsGenerator from './generators/REACT_SCRIPTS';
import sfcVueGenerator from './generators/SFC_VUE';
import updateOrganisationsGenerator from './generators/UPDATE_PACKAGE_ORGANIZATIONS';
import vueGenerator from './generators/VUE';
import webpackReactGenerator from './generators/WEBPACK_REACT';
import mithrilGenerator from './generators/MITHRIL';
import marionetteGenerator from './generators/MARIONETTE';
import markoGenerator from './generators/MARKO';
import htmlGenerator from './generators/HTML';
import webComponentsGenerator from './generators/WEB-COMPONENTS';
import riotGenerator from './generators/RIOT';
import preactGenerator from './generators/PREACT';
import svelteGenerator from './generators/SVELTE';
import raxGenerator from './generators/RAX';
import { warn } from './warn';
import { JsPackageManagerFactory, readPackageJson } from './js-package-manager';
import { NpmOptions } from './NpmOptions';
const logger = console;
type CommandOptions = {
useNpm?: boolean;
type?: any;
force?: any;
html?: boolean;
skipInstall?: boolean;
storyFormat?: StoryFormat;
parser?: string;
yes?: boolean;
};
const installStorybook = (projectType: ProjectType, options: CommandOptions): Promise<void> => {
const packageManager = JsPackageManagerFactory.getPackageManager(options.useNpm);
const npmOptions: NpmOptions = {
installAsDevDependencies: true,
skipInstall: options.skipInstall,
};
const language = detectLanguage();
const hasTSDependency = language === SupportedLanguage.TYPESCRIPT;
warn({ hasTSDependency });
const defaultStoryFormat = hasTSDependency ? StoryFormat.CSF_TYPESCRIPT : StoryFormat.CSF;
const generatorOptions = {
storyFormat: options.storyFormat || defaultStoryFormat,
language,
};
const end = () => {
if (!options.skipInstall) {
packageManager.installDependencies();
}
logger.log('\nTo run your Storybook, type:\n');
codeLog([packageManager.getRunStorybookCommand()]);
logger.log('\nFor more information visit:', chalk.cyan('https://storybook.js.org'));
// Add a new line for the clear visibility.
logger.log();
};
const REACT_NATIVE_REPO = 'https://github.com/storybookjs/react-native';
const runGenerator: () => Promise<void> = () => {
switch (projectType) {
case ProjectType.ALREADY_HAS_STORYBOOK:
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.
logger.log();
return Promise.resolve();
case ProjectType.UPDATE_PACKAGE_ORGANIZATIONS:
return updateOrganisationsGenerator(packageManager, options.parser, npmOptions)
.then(() => null) // commmandLog doesn't like to see output
.then(commandLog('Upgrading your project to the new Storybook packages.'))
.then(end);
case ProjectType.REACT_SCRIPTS:
return reactScriptsGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "Create React App" based project'))
.then(end);
case ProjectType.REACT:
return reactGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "React" app'))
.then(end);
case ProjectType.REACT_NATIVE: {
return (options.yes
? Promise.resolve({ server: true })
: (inquirer.prompt([
{
type: 'confirm',
name: 'server',
message:
'Do you want to install dependencies necessary to run Storybook server? You can manually do it later by install @storybook/react-native-server',
default: false,
},
]) as Promise<{ server: boolean }>)
)
.then(({ server }) =>
reactNativeGenerator(packageManager, npmOptions, server, generatorOptions)
)
.then(commandLog('Adding Storybook support to your "React Native" app'))
.then(end)
.then(() => {
logger.log(chalk.red('NOTE: installation is not 100% automated.'));
logger.log(`To quickly run Storybook, replace contents of your app entry with:\n`);
codeLog(["export {default} from './storybook';"]);
logger.log('\n For more in information, see the github readme:\n');
logger.log(chalk.cyan(REACT_NATIVE_REPO));
logger.log();
});
}
case ProjectType.METEOR:
return meteorGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "Meteor" app'))
.then(end);
case ProjectType.WEBPACK_REACT:
return webpackReactGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "Webpack React" app'))
.then(end);
case ProjectType.REACT_PROJECT:
return reactGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "React" library'))
.then(end);
case ProjectType.SFC_VUE:
return sfcVueGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "Single File Components Vue" app'))
.then(end);
case ProjectType.VUE:
return vueGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "Vue" app'))
.then(end);
case ProjectType.ANGULAR:
return angularGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "Angular" app'))
.then(end);
case ProjectType.EMBER:
return emberGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "Ember" app'))
.then(end);
case ProjectType.MITHRIL:
return mithrilGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "Mithril" app'))
.then(end);
case ProjectType.MARIONETTE:
return marionetteGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "Marionette.js" app'))
.then(end);
case ProjectType.MARKO:
return markoGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "Marko" app'))
.then(end);
case ProjectType.HTML:
return htmlGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "HTML" app'))
.then(end);
case ProjectType.WEB_COMPONENTS:
return webComponentsGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "web components" app'))
.then(end);
case ProjectType.RIOT:
return riotGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "riot.js" app'))
.then(end);
case ProjectType.PREACT:
return preactGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "Preact" app'))
.then(end);
case ProjectType.SVELTE:
return svelteGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "Svelte" app'))
.then(end);
case ProjectType.RAX:
return raxGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "Rax" app'))
.then(end);
case ProjectType.AURELIA:
return aureliaGenerator(packageManager, npmOptions, generatorOptions)
.then(commandLog('Adding Storybook support to your "Aurelia" app'))
.then(end);
default:
paddedLog(`We couldn't detect your project type. (code: ${projectType})`);
paddedLog(
'You can specify a project type explicitly via `sb init --type <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.
logger.log();
return projectTypeInquirer(options);
}
};
return runGenerator().catch((ex) => {
logger.error(`\n ${chalk.red(ex.stack)}`);
process.exit(1);
});
};
const projectTypeInquirer = async (options: { yes?: boolean }) => {
const manualAnswer = options.yes
? true
: await inquirer.prompt([
{
type: 'confirm',
name: 'manual',
message: 'Do you want to manually choose a Storybook project type to install?',
default: false,
},
]);
if (manualAnswer !== true && manualAnswer.manual) {
const frameworkAnswer = await inquirer.prompt([
{
type: 'list',
name: 'manualFramework',
message: 'Please choose a project type from the following list:',
choices: installableProjectTypes.map((type) => type.toUpperCase()),
},
]);
return installStorybook(frameworkAnswer.manualFramework, options);
}
return Promise.resolve();
};
export default function (options: CommandOptions, pkg: IPackage): Promise<void> {
const welcomeMessage = 'sb init - the simplest way to add a Storybook to your project.';
logger.log(chalk.inverse(`\n ${welcomeMessage} \n`));
// Update notify code.
new 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(readPackageJson(), options.force);
projectType = storybookInstalled
? ProjectType.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);
}