@storybook/react-native
Version:
A better way to develop React Native Components for your app
349 lines (336 loc) • 11.2 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
// scripts/common.js
var require_common = __commonJS({
"scripts/common.js"(exports2, module2) {
var { globToRegexp, serverRequire } = require("storybook/internal/common");
var path2 = require("path");
var fs = require("fs");
var cwd = process.cwd();
var toRequireContext = (specifier) => {
const { directory, files } = specifier;
const match = globToRegexp(`./${files}`);
return {
path: directory,
recursive: files.includes("**") || files.split("/").length > 1,
match
};
};
function requireUncached(module3) {
delete require.cache[require.resolve(module3)];
return serverRequire(module3);
}
var supportedExtensions = ["js", "jsx", "ts", "tsx", "cjs", "mjs"];
function getFilePathExtension({ configPath }, fileName) {
for (const ext of supportedExtensions) {
const filePath = path2.resolve(cwd, configPath, `${fileName}.${ext}`);
if (fs.existsSync(filePath)) {
return ext;
}
}
return null;
}
function getMain({ configPath }) {
const fileExtension = getFilePathExtension({ configPath }, "main");
if (fileExtension === null) {
throw new Error("main config file not found");
}
const mainPath = path2.resolve(cwd, configPath, `main.${fileExtension}`);
return requireUncached(mainPath);
}
function ensureRelativePathHasDot(relativePath) {
return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
}
function getPreviewExists({ configPath }) {
return !!getFilePathExtension({ configPath }, "preview");
}
function resolveAddonFile(addon, file, extensions = ["js", "mjs", "ts"], configPath) {
if (!addon || typeof addon !== "string")
return null;
try {
const basePath = `${addon}/${file}`;
require.resolve(basePath);
return basePath;
} catch (_error) {
}
for (const ext of extensions) {
try {
const filePath = `${addon}/${file}.${ext}`;
require.resolve(filePath);
return filePath;
} catch (_error) {
}
}
if (addon.startsWith("./") || addon.startsWith("../")) {
try {
const extension = getFilePathExtension({ configPath }, `${addon}/${file}`);
if (extension) {
return `${addon}/${file}`;
}
} catch (_error) {
}
}
return null;
}
function getAddonName(addon) {
if (typeof addon === "string")
return addon;
if (typeof addon === "object" && addon.name && typeof addon.name === "string")
return addon.name;
console.error("Invalid addon configuration", addon);
return null;
}
module2.exports = {
toRequireContext,
requireUncached,
getFilePathExtension,
getMain,
ensureRelativePathHasDot,
getPreviewExists,
resolveAddonFile,
getAddonName
};
}
});
// scripts/generate.js
var require_generate = __commonJS({
"scripts/generate.js"(exports2, module2) {
var {
toRequireContext,
ensureRelativePathHasDot,
getMain,
getPreviewExists,
resolveAddonFile,
getAddonName
} = require_common();
var { normalizeStories, globToRegexp } = require("storybook/internal/common");
var fs = require("fs");
var path2 = require("path");
var cwd = process.cwd();
function generate2({
configPath,
/* absolute = false, */
useJs = false,
docTools = true
}) {
const storybookRequiresLocation = path2.resolve(
cwd,
configPath,
`storybook.requires.${useJs ? "js" : "ts"}`
);
const mainImport = getMain({ configPath });
const main = mainImport.default ?? mainImport;
const storiesSpecifiers = normalizeStories(main.stories, {
configDir: configPath,
workingDir: cwd
});
const normalizedStories = storiesSpecifiers.map((specifier) => {
const reg = globToRegexp(`./${specifier.files}`);
const { path: p, recursive: r, match: m } = toRequireContext(specifier);
const pathToStory = ensureRelativePathHasDot(path2.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 registeredAddons = [];
for (const addon of main.addons) {
const registerPath = resolveAddonFile(
getAddonName(addon),
"register",
["js", "mjs", "jsx", "ts", "tsx"],
configPath
);
if (registerPath) {
registeredAddons.push(`import "${registerPath}";`);
}
}
const docToolsAnnotation = 'require("@storybook/react-native/preview")';
const enhancers = [];
if (docTools) {
enhancers.push(docToolsAnnotation);
}
for (const addon of main.addons) {
const previewPath = resolveAddonFile(
getAddonName(addon),
"preview",
["js", "mjs", "jsx", "ts", "tsx"],
configPath
);
if (previewPath) {
enhancers.push(`require('${previewPath}')`);
continue;
}
}
let options = "";
let optionsVar = "";
const reactNativeOptions = main.reactNative;
if (reactNativeOptions && typeof reactNativeOptions === "object") {
optionsVar = `const options = ${JSON.stringify(reactNativeOptions, null, 4)}`;
options = "options";
}
const previewExists = getPreviewExists({ configPath });
if (previewExists) {
enhancers.unshift("require('./preview')");
}
const annotations = `[
${enhancers.join(",\n ")}
]`;
const globalTypes = `
declare global {
var view: View;
var STORIES: typeof normalizedStories;
}
`;
const fileContent = `/* do not change this file, it is auto generated by storybook. */
import { start, updateView${useJs ? "" : ", View"} } from '@storybook/react-native';
${registeredAddons.join("\n")}
const normalizedStories = [
${normalizedStories.join(",\n")}
];
${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 ? ` ${options},` : ""}
});
} else {
updateView(global.view, annotations, normalizedStories${options ? `, ${options}` : ""});
}
export const view${useJs ? "" : ": View"} = global.view;
`;
fs.writeFileSync(storybookRequiresLocation, fileContent, {
encoding: "utf8",
flag: "w"
});
}
module2.exports = {
generate: generate2
};
}
});
// src/metro/withStorybook.ts
var path = __toESM(require("path"));
var import_generate = __toESM(require_generate());
var import_ws = require("ws");
function withStorybook(config, options = {
enabled: true,
useJs: false,
onDisabledRemoveStorybook: false,
docTools: true
}) {
const {
configPath,
enabled = true,
websockets,
useJs = false,
onDisabledRemoveStorybook = false,
docTools = true
} = options;
if (!enabled) {
if (onDisabledRemoveStorybook) {
return {
...config,
resolver: {
...config.resolver,
resolveRequest: (context, moduleName, platform) => {
const resolveFunction = config?.resolver?.resolveRequest ? config.resolver.resolveRequest : context.resolveRequest;
if (moduleName.startsWith("storybook") || moduleName.startsWith("@storybook")) {
return {
type: "empty"
};
}
return resolveFunction(context, moduleName, platform);
}
}
};
}
return config;
}
if (websockets) {
const port = websockets.port ?? 7007;
const host = websockets.host ?? "localhost";
const wss = new import_ws.WebSocketServer({ port, host });
wss.on("connection", function connection(ws) {
console.log("WebSocket connection established");
ws.on("error", console.error);
ws.on("message", function message(data) {
try {
const json = JSON.parse(data.toString());
wss.clients.forEach((wsClient) => wsClient.send(JSON.stringify(json)));
} catch (error) {
console.error(error);
}
});
});
}
(0, import_generate.generate)({
configPath: configPath ?? path.resolve(process.cwd(), "./.rnstorybook"),
useJs,
docTools
});
return {
...config,
transformer: {
...config.transformer,
unstable_allowRequireContext: true
},
resolver: {
...config.resolver,
resolveRequest: (context, moduleName, platform) => {
const resolveFunction = config?.resolver?.resolveRequest ? config.resolver.resolveRequest : context.resolveRequest;
const shouldUseCustomResolveConfig = moduleName.startsWith("storybook") || moduleName.startsWith("@storybook") || moduleName.startsWith("uuid");
const theContext = shouldUseCustomResolveConfig ? {
...context,
unstable_enablePackageExports: true,
unstable_conditionNames: ["import"]
} : context;
const resolveResult = resolveFunction(theContext, moduleName, platform);
if (resolveResult?.filePath?.includes?.("@storybook/react/template/cli")) {
return {
type: "empty"
};
}
return resolveResult;
}
}
};
}
module.exports = withStorybook;