2022-07-25 22:43:46 +10:00
|
|
|
import path from 'path';
|
2022-07-27 22:09:36 +10:00
|
|
|
import { remove, pathExists } from 'fs-extra';
|
|
|
|
import prompts from 'prompts';
|
2022-07-25 22:43:46 +10:00
|
|
|
|
2022-07-25 11:19:26 +10:00
|
|
|
import { getOptionsOrPrompt } from './utils/options';
|
2022-07-25 22:43:46 +10:00
|
|
|
import type { CLIStep } from './utils/cli-step';
|
|
|
|
import { executeCLIStep } from './utils/cli-step';
|
2022-07-25 11:19:26 +10:00
|
|
|
|
|
|
|
const frameworks = ['react'];
|
|
|
|
const addons = ['a11y', 'storysource'];
|
2022-07-26 16:12:07 +10:00
|
|
|
const examplesDir = path.resolve(__dirname, '../examples');
|
2022-07-25 11:19:26 +10:00
|
|
|
|
2022-07-25 22:43:46 +10:00
|
|
|
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: {
|
|
|
|
description:
|
|
|
|
"Include Storybook's own stories (only applies if a react-based framework is used)?",
|
|
|
|
},
|
|
|
|
create: {
|
|
|
|
description: 'Create the example from scratch (rather than degitting it)?',
|
|
|
|
},
|
2022-07-27 22:09:36 +10:00
|
|
|
forceDelete: {
|
|
|
|
description: 'Always delete an existing example, even if it has the same configuration?',
|
|
|
|
},
|
|
|
|
forceReuse: {
|
|
|
|
description: 'Always reusing an existing example, even if it has a different configuration?',
|
|
|
|
},
|
2022-07-25 22:43:46 +10:00
|
|
|
verdaccio: {
|
|
|
|
description: 'Use verdaccio rather than yarn linking stories?',
|
|
|
|
},
|
|
|
|
start: {
|
|
|
|
description: 'Start the example app?',
|
|
|
|
inverse: true,
|
|
|
|
},
|
|
|
|
build: {
|
|
|
|
description: 'Build the example app?',
|
|
|
|
},
|
|
|
|
watch: {
|
|
|
|
description: 'Start building used packages in watch mode as well as the example app?',
|
|
|
|
},
|
2022-07-26 16:20:49 +10:00
|
|
|
dryRun: {
|
|
|
|
description: "Don't execute commands, just list them?",
|
|
|
|
},
|
2022-07-25 22:43:46 +10:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-07-27 22:09:36 +10:00
|
|
|
const steps = {
|
2022-07-25 22:43:46 +10:00
|
|
|
repro: {
|
|
|
|
command: 'repro',
|
|
|
|
description: 'Bootstrapping example',
|
|
|
|
icon: '👷',
|
|
|
|
hasArgument: true,
|
|
|
|
options: {
|
|
|
|
template: { values: frameworks },
|
|
|
|
e2e: {},
|
|
|
|
},
|
2022-07-25 11:19:26 +10:00
|
|
|
},
|
2022-07-25 22:43:46 +10:00
|
|
|
add: {
|
|
|
|
command: 'add',
|
|
|
|
description: 'Adding addon',
|
|
|
|
icon: '+',
|
|
|
|
hasArgument: true,
|
|
|
|
options: {},
|
2022-07-25 11:19:26 +10:00
|
|
|
},
|
|
|
|
build: {
|
2022-07-25 22:43:46 +10:00
|
|
|
command: 'build',
|
|
|
|
description: 'Building example',
|
|
|
|
icon: '🔨',
|
|
|
|
options: {},
|
2022-07-25 11:19:26 +10:00
|
|
|
},
|
2022-07-25 22:43:46 +10:00
|
|
|
dev: {
|
|
|
|
command: 'dev',
|
|
|
|
description: 'Starting example',
|
2022-07-26 16:20:49 +10:00
|
|
|
icon: '🖥 ',
|
2022-07-25 22:43:46 +10:00
|
|
|
options: {},
|
2022-07-25 11:19:26 +10:00
|
|
|
},
|
2022-07-25 22:43:46 +10:00
|
|
|
};
|
|
|
|
|
|
|
|
async function main() {
|
|
|
|
const optionValues = await getOptions();
|
|
|
|
|
2022-07-27 22:09:36 +10:00
|
|
|
const { framework, forceDelete, forceReuse, dryRun } = optionValues;
|
2022-07-25 22:43:46 +10:00
|
|
|
const cwd = path.join(examplesDir, framework as string);
|
|
|
|
|
2022-07-27 22:09:36 +10:00
|
|
|
const exists = await pathExists(cwd);
|
|
|
|
let shouldReuse = exists && forceReuse;
|
|
|
|
if (exists && !forceDelete && !forceReuse) {
|
|
|
|
({ shouldReuse } = await prompts({
|
|
|
|
type: 'toggle',
|
|
|
|
message: `${path.relative(process.cwd(), cwd)} already exists, should we reuse it?`,
|
|
|
|
name: 'shouldReuse',
|
|
|
|
initial: true,
|
|
|
|
active: 'yes',
|
|
|
|
inactive: 'no',
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (exists && !shouldReuse) await remove(cwd);
|
|
|
|
|
|
|
|
if (!shouldReuse) {
|
2022-07-25 22:43:46 +10:00
|
|
|
await executeCLIStep(steps.repro, {
|
|
|
|
argument: cwd,
|
|
|
|
optionValues: { template: framework },
|
|
|
|
cwd: examplesDir,
|
2022-07-26 16:20:49 +10:00
|
|
|
dryRun,
|
2022-07-25 22:43:46 +10:00
|
|
|
});
|
|
|
|
|
|
|
|
// 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 });
|
2022-07-25 22:43:46 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO copy stories
|
|
|
|
}
|
|
|
|
|
|
|
|
const { start } = optionValues;
|
|
|
|
if (start) {
|
2022-07-26 16:20:49 +10:00
|
|
|
await executeCLIStep(steps.dev, { cwd, dryRun });
|
2022-07-25 22:43:46 +10:00
|
|
|
} else {
|
2022-07-26 16:20:49 +10:00
|
|
|
await executeCLIStep(steps.build, { cwd, dryRun });
|
2022-07-25 22:43:46 +10:00
|
|
|
// TODO serve
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO start dev
|
|
|
|
}
|
|
|
|
|
|
|
|
main().catch((err) => console.error(err));
|