@storybook/react-native
Version:
A better way to develop React Native Components for your app
272 lines (262 loc) • 9.74 kB
JavaScript
const require_chunk = require("./chunk-Ble4zEEl.js");
const require_buildIndex = require("./buildIndex-l9rzAl79.js");
//#region scripts/require-interop.js
var require_require_interop = /* @__PURE__ */ require_chunk.__commonJSMin(((exports, module) => {
let registered = false;
function interopRequireDefault(filePath) {
const hasEsbuildBeenRegistered = !!require("module")._extensions[".ts"];
if (registered === false && !hasEsbuildBeenRegistered) {
const { register } = require("esbuild-register/dist/node");
registered = true;
register({
target: `node${process.version.slice(1)}`,
format: "cjs",
hookIgnoreNodeModules: true,
keepNames: true,
tsconfigRaw: `{
"compilerOptions": {
"strict": false,
"skipLibCheck": true,
},
}`
});
}
const result = require(filePath);
return typeof result === "object" && result !== null && typeof result.default !== "undefined" ? result.default : result;
}
module.exports = { interopRequireDefault };
}));
//#endregion
//#region scripts/generate.js
var require_generate = /* @__PURE__ */ require_chunk.__commonJSMin(((exports, module) => {
const { toRequireContext, ensureRelativePathHasDot, getPreviewExists, resolveAddonFile, getAddonName } = require_buildIndex.require_common();
const { normalizeStories, globToRegexp, loadMainConfig, getInterpretedFile } = require("storybook/internal/common");
const { interopRequireDefault } = require_require_interop();
const fs = require("fs");
const { networkInterfaces } = require("node:os");
const path = require("path");
const cwd = process.cwd();
const MAIN_ADDONS_DEPRECATION_URL = "https://github.com/storybookjs/react-native/blob/main/MIGRATION.md#deprecating-addons-in-rnstorybook-main";
/**
* @param {{ addons?: unknown[] }} main
* @param {string} configPath
*
* @todo Remove support for `main.addons` in a future major version.
*/
function warnDeprecatedMainAddonsField(main, configPath) {
const addons = main.addons ?? [];
if (addons.length === 0) return;
const names = addons.map((addon) => getAddonName(addon)).filter((name) => typeof name === "string");
const list = [...new Set(names)].join(", ");
console.warn(`[Storybook React Native] The \`addons\` field in your main config (${configPath}) is deprecated and will be removed in a future major version.\nMove every entry to \`deviceAddons\` instead. That includes on-device UI packages (\`@storybook/addon-ondevice-*\`), other addons you bundle with the app (for example storybook-addon-deep-controls), and local paths such as ./my-addon.\n` + (list ? `Still listed under \`addons\`: ${list}.\n` : "") + `Details: ${MAIN_ADDONS_DEPRECATION_URL}`);
}
const loadMain = async ({ configPath, cwd }) => {
try {
return await loadMainConfig({
configDir: configPath,
cwd
});
} catch {
console.error("Error loading main config, trying fallback");
}
const mainPath = getInterpretedFile(path.resolve(cwd, configPath, "main"));
if (!mainPath) throw new Error(`Main config file not found in ${path.resolve(cwd, configPath)}`);
return interopRequireDefault(mainPath);
};
/**
* Get the local IP address of the machine.
* @returns The local IP address of the machine.
*/
function getLocalIPAddress() {
const nets = networkInterfaces();
for (const name of Object.keys(nets)) for (const net of nets[name]) {
const familyV4Value = typeof net.family === "string" ? "IPv4" : 4;
if (net.family === familyV4Value && !net.internal) return net.address;
}
return "0.0.0.0";
}
/**
* @param {{
* configPath: string;
* useJs?: boolean;
* docTools?: boolean;
* host?: string;
* port?: number;
* secured?: boolean;
* disableUI?: boolean;
* }} generateOptions
*/
async function generate(generateOptions) {
const { configPath, useJs = false, docTools = true, host = void 0, port = void 0, secured = false, disableUI = false } = generateOptions;
const channelHost = host === "auto" ? getLocalIPAddress() : host;
const storybookRequiresLocation = path.resolve(cwd, configPath, `storybook.requires.${useJs ? "js" : "ts"}`);
const main = await loadMain({
configPath,
cwd
});
warnDeprecatedMainAddonsField(main, configPath);
const normalizedStories = normalizeStories(main.stories, {
configDir: configPath,
workingDir: cwd
}).map((specifier) => {
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}/,
req: require.context(
'${pathToStory}',
${r},
${m}
),
}`;
});
const registeredAddons = [];
const allAddons = [...main.addons ?? [], ...main.deviceAddons ?? []];
for (const addon of allAddons) {
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 allAddons) {
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 (disableUI) reactNativeOptions.disableUI = true;
if (reactNativeOptions && typeof reactNativeOptions === "object") {
optionsVar = `const options = ${JSON.stringify(reactNativeOptions, null, 2)}`;
options = "options";
}
let featuresAssignment = "";
const features = main.features;
if (features && typeof features === "object") {
const featureEntries = Object.entries(features).filter(([, value]) => typeof value === "boolean");
if (featureEntries.length > 0) featuresAssignment = featureEntries.map(([key, value]) => `globalThis.FEATURES.${key} = ${value};`).join("\n");
}
if (getPreviewExists({ configPath })) enhancers.unshift("require('./preview')");
const annotations = `[
${enhancers.join(",\n ")}
]`;
const hasWebsocketConfig = host !== void 0 || port !== void 0 || secured;
const websocketAssignmentLines = [];
if (channelHost) websocketAssignmentLines.push(`host: '${channelHost}',`);
if (hasWebsocketConfig) {
websocketAssignmentLines.push(`port: ${port ?? 7007},`);
websocketAssignmentLines.push(`secured: ${Boolean(secured)},`);
}
const fileContent = `/* do not change this file, it is auto generated by storybook. */
${useJs ? "" : "/// <reference types=\"@storybook/react-native/metro-env\" />\n"}import { start, updateView${useJs ? "" : ", View, type Features"} } from '@storybook/react-native';
${registeredAddons.join("\n")}
const normalizedStories = [
${normalizedStories.join(",\n ")}
];
${useJs ? "" : `
declare global {
var view: View;
var STORIES: typeof normalizedStories;
var STORYBOOK_WEBSOCKET:
| { host?: string; port?: number; secured?: boolean }
| undefined;
var FEATURES: Features;
}
`}
const annotations = ${annotations};
globalThis.STORIES = normalizedStories;
${hasWebsocketConfig ? `globalThis.STORYBOOK_WEBSOCKET = {
${websocketAssignmentLines.join("\n ")}
};` : ""}
module?.hot?.accept?.();
${featuresAssignment ? `\n${featuresAssignment}\n` : ""}
${optionsVar}
if (!globalThis.view) {
globalThis.view = start({
annotations,
storyEntries: normalizedStories,
${options ? ` ${options},` : ""}
});
} else {
updateView(globalThis.view, annotations, normalizedStories${options ? `, ${options}` : ""});
}
export const view${useJs ? "" : ": View"} = globalThis.view;
`;
fs.writeFileSync(storybookRequiresLocation, fileContent, {
encoding: "utf8",
flag: "w"
});
}
module.exports = { generate };
}));
//#endregion
//#region src/env-tools.ts
function envVariableToBoolean(value, defaultValue = false) {
switch (value) {
case "true": return true;
case "false": return false;
default: return !!defaultValue;
}
}
function envVariableToString(value, defaultValue) {
return value ?? defaultValue;
}
function envVariableToNumber(value, defaultValue) {
const parsed = parseInt(value ?? "", 10);
if (!isNaN(parsed)) return parsed;
return defaultValue;
}
function loadWebsocketEnvOverrides(websockets) {
const envHost = envVariableToString(process.env.STORYBOOK_WS_HOST, websockets === "auto" ? void 0 : websockets?.host ?? void 0);
const envPort = envVariableToNumber(process.env.STORYBOOK_WS_PORT, websockets === "auto" ? 7007 : websockets?.port ?? 7007);
const envSecured = envVariableToBoolean(process.env.STORYBOOK_WS_SECURED);
if (websockets === void 0 && !envHost) return {
host: void 0,
port: void 0,
secured: false
};
const config = websockets === "auto" || websockets === void 0 ? {} : { ...websockets };
if (envHost) config.host = envHost;
if (envPort) config.port = envPort;
if (envSecured) config.secured = true;
return config;
}
//#endregion
Object.defineProperty(exports, "envVariableToBoolean", {
enumerable: true,
get: function() {
return envVariableToBoolean;
}
});
Object.defineProperty(exports, "loadWebsocketEnvOverrides", {
enumerable: true,
get: function() {
return loadWebsocketEnvOverrides;
}
});
Object.defineProperty(exports, "require_generate", {
enumerable: true,
get: function() {
return require_generate;
}
});