@storybook/react-native
Version:
A better way to develop React Native Components for your app
122 lines (90 loc) • 3.23 kB
JavaScript
const {
toRequireContext,
ensureRelativePathHasDot,
getMain,
getPreviewExists,
} = require('./common');
const { normalizeStories, globToRegexp } = require('@storybook/core/common');
const fs = require('fs');
const prettier = require('prettier');
const path = require('path');
const cwd = process.cwd();
function generate({ configPath, absolute = false, useJs = false }) {
const storybookRequiresLocation = path.resolve(
cwd,
configPath,
`storybook.requires.${useJs ? 'js' : 'ts'}`
);
const mainImport = getMain({ configPath });
const main = mainImport.default ?? mainImport;
// const reactNativeOptions = main.reactNativeOptions;
const storiesSpecifiers = normalizeStories(main.stories, {
configDir: configPath,
workingDir: cwd,
});
const normalizedStories = storiesSpecifiers.map((specifier) => {
// TODO why????
const reg = globToRegexp(`./${specifier.files}`);
const { path: p, recursive: r, match: m } = toRequireContext(specifier);
const pathToStory = ensureRelativePathHasDot(path.posix.relative(configPath, p));
return `{
titlePrefix: "${specifier.titlePrefix}",
directory: "${specifier.directory}",
files: "${specifier.files}",
importPathMatcher: /${reg.source}/,
${useJs ? '' : '// @ts-ignore'}
req: require.context('${pathToStory}', ${r}, ${m})
}`;
});
const registerAddons = main.addons?.map((addon) => `import "${addon}/register";`).join('\n');
const doctools = 'require("@storybook/react-native/dist/preview")';
// TODO: implement presets or something similar
const enhancer = main.addons?.includes('@storybook/addon-ondevice-actions')
? "require('@storybook/addon-actions/preview')"
: '';
let options = '';
let optionsVar = '';
const reactNativeOptions = main.reactNative;
if (reactNativeOptions && typeof reactNativeOptions === 'object') {
optionsVar = `const options = ${JSON.stringify(reactNativeOptions)}`;
options = 'options';
}
const previewExists = getPreviewExists({ configPath });
const annotations = `[${previewExists ? "require('./preview')," : ''}${doctools}, ${enhancer}]`;
const globalTypes = `
declare global {
var view: ReturnType<typeof start>;
var STORIES: typeof normalizedStories;
}
`;
const fileContent = `
/* do not change this file, it is auto generated by storybook. */
import { start, updateView } from '@storybook/react-native';
${registerAddons}
const normalizedStories = [${normalizedStories.join(',')}];
${useJs ? '' : globalTypes}
const annotations = ${annotations};
global.STORIES = normalizedStories;
${useJs ? '' : '// @ts-ignore'}
module?.hot?.accept?.();
${optionsVar}
if (!global.view) {
global.view = start({
annotations,
storyEntries: normalizedStories,
${options}
});
} else {
updateView(global.view, annotations, normalizedStories, ${options});
}
export const view = global.view;
`;
const formattedFileContent = prettier.format(fileContent, { parser: 'babel-ts' });
fs.writeFileSync(storybookRequiresLocation, formattedFileContent, {
encoding: 'utf8',
flag: 'w',
});
}
module.exports = {
generate,
};