storybook/scripts/example.ts

174 lines
4.5 KiB
TypeScript
Raw Normal View History

import path from 'path';
import { remove, pathExists } from 'fs-extra';
import prompts from 'prompts';
import { getOptionsOrPrompt } from './utils/options';
import { executeCLIStep } from './utils/cli-step';
import { exec } from '../code/lib/cli/src/repro-generators/scripts';
2022-07-28 20:15:57 +10:00
const frameworks = ['react', 'angular'];
const addons = ['a11y', 'storysource'];
2022-07-26 16:12:07 +10:00
const examplesDir = path.resolve(__dirname, '../examples');
2022-07-28 21:21:58 +10:00
const codeDir = path.resolve(__dirname, '../code');
async function getOptions() {
return getOptionsOrPrompt('yarn example', {
framework: {
description: 'Which framework would you like to use?',
values: frameworks,
required: true,
},
addon: {
description: 'Which extra addons (beyond the CLI defaults) would you like installed?',
values: addons,
multiple: true,
},
includeStories: {
2022-07-28 20:15:57 +10:00
description: "Include Storybook's own stories?",
promptType: (_, { framework }) => framework === 'react',
},
create: {
description: 'Create the example from scratch (rather than degitting it)?',
},
forceDelete: {
description: 'Always delete an existing example, even if it has the same configuration?',
2022-07-28 20:15:57 +10:00
promptType: false,
},
forceReuse: {
2022-07-28 19:46:40 +10:00
description: 'Always reuse an existing example, even if it has a different configuration?',
2022-07-28 20:15:57 +10:00
promptType: false,
},
2022-07-28 19:46:40 +10:00
link: {
description: 'Link the storybook to the local code?',
inverse: true,
},
start: {
2022-07-28 19:46:40 +10:00
description: 'Start the example Storybook?',
inverse: true,
},
build: {
2022-07-28 19:46:40 +10:00
description: 'Build the example Storybook?',
},
watch: {
2022-07-28 19:46:40 +10:00
description: 'Start building used packages in watch mode as well as the example Storybook?',
},
2022-07-26 16:20:49 +10:00
dryRun: {
2022-07-28 19:46:40 +10:00
description: "Don't execute commands, just list them (dry run)?",
2022-07-26 16:20:49 +10:00
},
});
}
const steps = {
repro: {
command: 'repro',
description: 'Bootstrapping example',
icon: '👷',
hasArgument: true,
options: {
template: { values: frameworks },
e2e: {},
},
},
add: {
command: 'add',
description: 'Adding addon',
icon: '+',
hasArgument: true,
options: {},
},
2022-07-28 21:21:58 +10:00
link: {
command: 'link',
description: 'Linking packages',
icon: '🔗',
hasArgument: true,
options: { local: {} },
},
build: {
command: 'build',
description: 'Building example',
icon: '🔨',
options: {},
},
dev: {
command: 'dev',
description: 'Starting example',
2022-07-26 16:20:49 +10:00
icon: '🖥 ',
options: {},
},
};
async function main() {
const optionValues = await getOptions();
2022-07-28 21:21:58 +10:00
const { framework, forceDelete, forceReuse, link, dryRun } = optionValues;
const cwd = path.join(examplesDir, framework as string);
const exists = await pathExists(cwd);
2022-07-28 19:46:40 +10:00
let shouldDelete = exists && !forceReuse;
if (exists && !forceDelete && !forceReuse) {
2022-07-28 19:46:40 +10:00
const relativePath = path.relative(process.cwd(), cwd);
({ shouldDelete } = await prompts({
type: 'toggle',
2022-07-28 19:46:40 +10:00
message: `${relativePath} already exists, should delete it and create a new one?`,
name: 'shouldDelete',
initial: false,
active: 'yes',
inactive: 'no',
}));
}
2022-07-28 19:46:40 +10:00
if (exists && shouldDelete && !dryRun) await remove(cwd);
2022-07-28 19:46:40 +10:00
if (!exists || shouldDelete) {
await executeCLIStep(steps.repro, {
argument: cwd,
optionValues: { template: framework },
cwd: examplesDir,
2022-07-26 16:20:49 +10:00
dryRun,
});
// TODO -- sb add <addon> doesn't actually work properly:
// - installs in `deps` not `devDeps`
// - does a `workspace:^` install (what does that mean?)
// - doesn't add to `main.js`
// eslint-disable-next-line no-restricted-syntax
for (const addon of optionValues.addon as string[]) {
const addonName = `@storybook/addon-${addon}`;
// eslint-disable-next-line no-await-in-loop
2022-07-26 16:20:49 +10:00
await executeCLIStep(steps.add, { argument: addonName, cwd, dryRun });
}
// TODO copy stories
2022-07-28 21:21:58 +10:00
if (link) {
await executeCLIStep(steps.link, {
argument: cwd,
cwd: codeDir,
dryRun,
optionValues: { local: true },
});
}
}
const { start } = optionValues;
if (start) {
await exec(
'yarn storybook',
{ cwd },
{
dryRun,
startMessage: `⬆️ Starting Storybook`,
errorMessage: `🚨 Starting Storybook failed`,
}
);
} else {
2022-07-26 16:20:49 +10:00
await executeCLIStep(steps.build, { cwd, dryRun });
// TODO serve
}
// TODO start dev
}
main().catch((err) => console.error(err));