@storybook/react-native
Version:
A better way to develop React Native Components for your app
327 lines (321 loc) • 11.8 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 __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
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
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// scripts/common.js
var require_common = __commonJS({
"scripts/common.js"(exports2, module2) {
var { globToRegexp } = require("storybook/internal/common");
var path2 = require("path");
var fs = require("fs");
var cwd2 = process.cwd();
var toRequireContext = (specifier) => {
const { directory, files } = specifier;
const match = globToRegexp(`./${files}`);
return {
path: directory,
recursive: files.includes("**") || files.split("/").length > 1,
match
};
};
var supportedExtensions = ["js", "jsx", "ts", "tsx", "cjs", "mjs"];
function getFilePathExtension({ configPath }, fileName) {
for (const ext of supportedExtensions) {
const filePath = path2.resolve(cwd2, configPath, `${fileName}.${ext}`);
if (fs.existsSync(filePath)) {
return ext;
}
}
return null;
}
function getFilePathWithExtension2({ configPath }, fileName) {
for (const ext of supportedExtensions) {
const filePath = path2.resolve(cwd2, configPath, `${fileName}.${ext}`);
if (fs.existsSync(filePath)) {
return filePath;
}
}
return null;
}
function ensureRelativePathHasDot2(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;
const resolvePaths = { paths: [cwd2] };
try {
const basePath = `${addon}/${file}`;
require.resolve(basePath, resolvePaths);
return basePath;
} catch (_error) {
}
for (const ext of extensions) {
try {
const filePath = `${addon}/${file}.${ext}`;
require.resolve(filePath, resolvePaths);
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,
getFilePathExtension,
ensureRelativePathHasDot: ensureRelativePathHasDot2,
getPreviewExists,
resolveAddonFile,
getAddonName,
getFilePathWithExtension: getFilePathWithExtension2
};
}
});
// src/node.ts
var node_exports = {};
__export(node_exports, {
buildIndex: () => buildIndex,
createChannelServer: () => createChannelServer
});
module.exports = __toCommonJS(node_exports);
// src/metro/channelServer.ts
var import_ws = require("ws");
var import_node_http = require("http");
// src/metro/buildIndex.ts
var import_common = require("storybook/internal/common");
var import_node_fs = require("fs");
var import_glob = require("glob");
var import_path = __toESM(require("path"));
var import_csf_tools = require("storybook/internal/csf-tools");
var import_csf = require("storybook/internal/csf");
var import_preview_api = require("storybook/internal/preview-api");
var import_common2 = __toESM(require_common());
var cwd = process.cwd();
var makeTitle = (fileName, specifier, userTitle) => {
const title = (0, import_preview_api.userOrAutoTitleFromSpecifier)(fileName, specifier, userTitle);
if (title) {
return title.replace("./", "");
} else if (userTitle) {
return userTitle.replace("./", "");
} else {
console.error("Could not generate title!!");
process.exit(1);
}
};
function ensureRelativePathHasDot(relativePath) {
return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
}
async function buildIndex({ configPath }) {
const main = await (0, import_common.loadMainConfig)({ configDir: configPath, cwd });
if (!main.stories || !Array.isArray(main.stories)) {
throw new Error("No stories found");
}
const storiesSpecifiers = (0, import_common.normalizeStories)(main.stories, {
configDir: configPath,
workingDir: cwd
});
const specifierStoryPaths = storiesSpecifiers.map((specifier) => {
return (0, import_glob.sync)(specifier.files, {
cwd: import_path.default.resolve(process.cwd(), specifier.directory),
absolute: true,
// default to always ignore (exclude) anything in node_modules
ignore: ["**/node_modules"]
}).map((storyPath) => {
const normalizePathForWindows = (str) => import_path.default.sep === "\\" ? str.replace(/\\/g, "/") : str;
return normalizePathForWindows(storyPath);
});
});
const csfStories = specifierStoryPaths.reduce(
(acc, specifierStoryPathList, specifierIndex) => {
const paths = specifierStoryPathList.map((storyPath) => {
const code = (0, import_node_fs.readFileSync)(storyPath, { encoding: "utf-8" }).toString();
const relativePath = ensureRelativePathHasDot(import_path.default.posix.relative(cwd, storyPath));
return {
result: (0, import_csf_tools.loadCsf)(code, {
fileName: storyPath,
makeTitle: (userTitle) => makeTitle(relativePath, storiesSpecifiers[specifierIndex], userTitle)
}).parse(),
specifier: storiesSpecifiers[specifierIndex],
fileName: relativePath
};
});
return [...acc, ...paths];
},
new Array()
);
const index = {
v: 5,
entries: {}
};
for (const { result, specifier, fileName } of csfStories) {
const { meta, stories } = result;
if (stories && stories.length > 0) {
for (const story of stories) {
const id = (0, import_csf.toId)(meta.title, story.name);
index.entries[id] = {
type: "story",
subtype: "story",
id,
name: story.name,
title: meta.title,
importPath: `${specifier.directory}/${import_path.default.posix.relative(specifier.directory, fileName)}`,
tags: ["story"]
};
}
} else {
console.log(`No stories found for ${fileName}`);
}
}
try {
const previewPath = (0, import_common2.getFilePathWithExtension)({ configPath }, "preview");
const previewSourceCode = (0, import_node_fs.readFileSync)(previewPath, { encoding: "utf-8" }).toString();
const storySort = (0, import_csf_tools.getStorySortParameter)(previewSourceCode);
const sortableStories = Object.values(index.entries);
(0, import_preview_api.sortStoriesV7)(
sortableStories,
storySort,
sortableStories.map((entry) => entry.importPath)
);
const sorted = sortableStories.reduce(
(acc, item) => {
acc[item.id] = item;
return acc;
},
{}
);
return { v: 5, entries: sorted };
} catch {
console.warn("Failed to sort stories, using unordered index");
return index;
}
}
// src/metro/channelServer.ts
function createChannelServer({
port = 7007,
host = void 0,
configPath
}) {
const httpServer = (0, import_node_http.createServer)(async (req, res) => {
if (req.method === "OPTIONS") {
res.writeHead(204);
res.end();
return;
}
if (req.method === "GET" && req.url === "/index.json") {
try {
const index = await buildIndex({ configPath });
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify(index));
} catch (error) {
console.error("Failed to build index:", error);
res.writeHead(500, { "Content-Type": "application/json" });
res.end(JSON.stringify({ error: "Failed to build story index" }));
}
return;
}
if (req.method === "POST" && req.url === "/send-event") {
let body = "";
req.on("data", (chunk) => {
body += chunk.toString();
});
req.on("end", () => {
try {
const json = JSON.parse(body);
wss.clients.forEach((wsClient) => wsClient.send(JSON.stringify(json)));
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ success: true }));
} catch (error) {
console.error("Failed to parse event:", error);
res.writeHead(400, { "Content-Type": "application/json" });
res.end(JSON.stringify({ success: false, error: "Invalid JSON" }));
}
});
return;
}
res.writeHead(404, { "Content-Type": "application/json" });
res.end(JSON.stringify({ error: "Not found" }));
});
const wss = new import_ws.WebSocketServer({ server: httpServer });
wss.on("error", () => {
});
setInterval(function ping() {
wss.clients.forEach(function each(client) {
if (client.readyState === import_ws.WebSocket.OPEN) {
client.send(JSON.stringify({ type: "ping", args: [] }));
}
});
}, 1e4);
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);
}
});
});
httpServer.on("error", (error) => {
if (error.code === "EADDRINUSE") {
console.warn(
`[Storybook] Port ${port} is already in use. The channel server will not start. Another instance may already be running.`
);
} else {
console.error(`[Storybook] Channel server error:`, error);
}
});
httpServer.listen(port, host, () => {
console.log(`WebSocket server listening on ${host ?? "localhost"}:${port}`);
});
return wss;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
buildIndex,
createChannelServer
});