UNPKG

storybook

Version:

Storybook: Develop, document, and test UI components in isolation

1,199 lines (1,167 loc) • 39.3 kB
import CJS_COMPAT_NODE_URL_q99y7iqlbzn from 'node:url'; import CJS_COMPAT_NODE_PATH_q99y7iqlbzn from 'node:path'; import CJS_COMPAT_NODE_MODULE_q99y7iqlbzn from "node:module"; var __filename = CJS_COMPAT_NODE_URL_q99y7iqlbzn.fileURLToPath(import.meta.url); var __dirname = CJS_COMPAT_NODE_PATH_q99y7iqlbzn.dirname(__filename); var require = CJS_COMPAT_NODE_MODULE_q99y7iqlbzn.createRequire(import.meta.url); // ------------------------------------------------------------ // end of CJS compatibility banner, injected by Storybook's esbuild configuration // ------------------------------------------------------------ import { version } from "./chunk-D2RKDVXH.js"; import { createFileSystemCache, resolvePathInStorybookCache, up } from "./chunk-CIADIQ6F.js"; import { globalSettings } from "./chunk-AOVN24BT.js"; import { execaCommand, getProjectRoot } from "./chunk-CWTRQZTU.js"; import { getSessionId, nanoid, set } from "./chunk-ZHQALUV5.js"; import { resolvePackageDir } from "./chunk-7N53RHGS.js"; import { slash } from "./chunk-ALHPYGYU.js"; import { require_picocolors } from "./chunk-KABHBSS3.js"; import { __commonJS, __name, __toESM } from "./chunk-MB5KTO7X.js"; // ../node_modules/fetch-retry/index.js var require_fetch_retry = __commonJS({ "../node_modules/fetch-retry/index.js"(exports, module) { "use strict"; module.exports = function(fetch2, defaults) { defaults = defaults || {}; if (typeof fetch2 !== "function") { throw new ArgumentError("fetch must be a function"); } if (typeof defaults !== "object") { throw new ArgumentError("defaults must be an object"); } if (defaults.retries !== void 0 && !isPositiveInteger(defaults.retries)) { throw new ArgumentError("retries must be a positive integer"); } if (defaults.retryDelay !== void 0 && !isPositiveInteger(defaults.retryDelay) && typeof defaults.retryDelay !== "function") { throw new ArgumentError("retryDelay must be a positive integer or a function returning a positive integer"); } if (defaults.retryOn !== void 0 && !Array.isArray(defaults.retryOn) && typeof defaults.retryOn !== "function") { throw new ArgumentError("retryOn property expects an array or function"); } var baseDefaults = { retries: 3, retryDelay: 1e3, retryOn: [] }; defaults = Object.assign(baseDefaults, defaults); return /* @__PURE__ */ __name(function fetchRetry(input, init) { var retries = defaults.retries; var retryDelay = defaults.retryDelay; var retryOn = defaults.retryOn; if (init && init.retries !== void 0) { if (isPositiveInteger(init.retries)) { retries = init.retries; } else { throw new ArgumentError("retries must be a positive integer"); } } if (init && init.retryDelay !== void 0) { if (isPositiveInteger(init.retryDelay) || typeof init.retryDelay === "function") { retryDelay = init.retryDelay; } else { throw new ArgumentError("retryDelay must be a positive integer or a function returning a positive integer"); } } if (init && init.retryOn) { if (Array.isArray(init.retryOn) || typeof init.retryOn === "function") { retryOn = init.retryOn; } else { throw new ArgumentError("retryOn property expects an array or function"); } } return new Promise(function(resolve, reject) { var wrappedFetch = /* @__PURE__ */ __name(function(attempt) { var _input = typeof Request !== "undefined" && input instanceof Request ? input.clone() : input; fetch2(_input, init).then(function(response) { if (Array.isArray(retryOn) && retryOn.indexOf(response.status) === -1) { resolve(response); } else if (typeof retryOn === "function") { try { return Promise.resolve(retryOn(attempt, null, response)).then(function(retryOnResponse) { if (retryOnResponse) { retry2(attempt, null, response); } else { resolve(response); } }).catch(reject); } catch (error) { reject(error); } } else { if (attempt < retries) { retry2(attempt, null, response); } else { resolve(response); } } }).catch(function(error) { if (typeof retryOn === "function") { try { Promise.resolve(retryOn(attempt, error, null)).then(function(retryOnResponse) { if (retryOnResponse) { retry2(attempt, error, null); } else { reject(error); } }).catch(function(error2) { reject(error2); }); } catch (error2) { reject(error2); } } else if (attempt < retries) { retry2(attempt, error, null); } else { reject(error); } }); }, "wrappedFetch"); function retry2(attempt, error, response) { var delay = typeof retryDelay === "function" ? retryDelay(attempt, error, response) : retryDelay; setTimeout(function() { wrappedFetch(++attempt); }, delay); } __name(retry2, "retry"); wrappedFetch(0); }); }, "fetchRetry"); }; function isPositiveInteger(value) { return Number.isInteger(value) && value >= 0; } __name(isPositiveInteger, "isPositiveInteger"); function ArgumentError(message) { this.name = "ArgumentError"; this.message = message; } __name(ArgumentError, "ArgumentError"); } }); // src/telemetry/index.ts import { logger as logger2 } from "storybook/internal/node-logger"; // src/telemetry/notify.ts var import_picocolors = __toESM(require_picocolors(), 1); import { cache } from "storybook/internal/common"; import { CLI_COLORS, logger } from "storybook/internal/node-logger"; var TELEMETRY_KEY_NOTIFY_DATE = "telemetry-notification-date"; var notify = /* @__PURE__ */ __name(async () => { const telemetryNotifyDate = await cache.get(TELEMETRY_KEY_NOTIFY_DATE, null); if (telemetryNotifyDate) { return; } cache.set(TELEMETRY_KEY_NOTIFY_DATE, Date.now()); logger.log( `${CLI_COLORS.info("Attention:")} Storybook now collects completely anonymous telemetry regarding usage. This information is used to shape Storybook's roadmap and prioritize features.` ); logger.log( `You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:` ); logger.log(import_picocolors.default.cyan("https://storybook.js.org/telemetry")); logger.log(""); }, "notify"); // src/telemetry/sanitize.ts import path from "node:path"; function regexpEscape(str) { return str.replace(/[-[/{}()*+?.\\^$|]/g, `\\$&`); } __name(regexpEscape, "regexpEscape"); function removeAnsiEscapeCodes(input = "") { return input.replace(/\u001B\[[0-9;]*m/g, ""); } __name(removeAnsiEscapeCodes, "removeAnsiEscapeCodes"); function cleanPaths(str, separator = path.sep) { if (!str) { return str; } const stack = process.cwd().split(separator); while (stack.length > 1) { const currentPath = stack.join(separator); const currentRegex = new RegExp(regexpEscape(currentPath), `gi`); str = str.replace(currentRegex, `$SNIP`); const currentPath2 = stack.join(separator + separator); const currentRegex2 = new RegExp(regexpEscape(currentPath2), `gi`); str = str.replace(currentRegex2, `$SNIP`); stack.pop(); } return str; } __name(cleanPaths, "cleanPaths"); function sanitizeError(error, pathSeparator = path.sep) { try { error = { ...JSON.parse(JSON.stringify(error)), message: removeAnsiEscapeCodes(error.message), stack: removeAnsiEscapeCodes(error.stack), cause: error.cause, name: error.name }; const errorString = cleanPaths(JSON.stringify(error), pathSeparator); return JSON.parse(errorString); } catch (err) { return `Sanitization error: ${err?.message}`; } } __name(sanitizeError, "sanitizeError"); // src/telemetry/storybook-metadata.ts import { readFile } from "node:fs/promises"; import { dirname } from "node:path"; import { getStorybookConfiguration, getStorybookInfo, isCI, loadMainConfig, versions } from "storybook/internal/common"; import { readConfig } from "storybook/internal/csf-tools"; // src/telemetry/get-application-file-count.ts import { sep } from "node:path"; // src/telemetry/exec-command-count-lines.ts import { createInterface } from "node:readline"; async function execCommandCountLines(command, options) { const process3 = execaCommand(command, { shell: true, buffer: false, ...options }); if (!process3.stdout) { throw new Error("Unexpected missing stdout"); } let lineCount = 0; const rl = createInterface(process3.stdout); rl.on("line", () => { lineCount += 1; }); await process3; rl.close(); return lineCount; } __name(execCommandCountLines, "execCommandCountLines"); // src/telemetry/run-telemetry-operation.ts var cache2 = createFileSystemCache({ basePath: resolvePathInStorybookCache("telemetry"), ns: "storybook", ttl: 24 * 60 * 60 * 1e3 // 24h }); var runTelemetryOperation = /* @__PURE__ */ __name(async (cacheKey, operation) => { let cached = await cache2.get(cacheKey); if (cached === void 0) { cached = await operation(); if (cached !== void 0) { await cache2.set(cacheKey, cached); } } return cached; }, "runTelemetryOperation"); // src/telemetry/get-application-file-count.ts var nameMatches = ["page", "screen"]; var extensions = ["js", "jsx", "ts", "tsx"]; var getApplicationFilesCountUncached = /* @__PURE__ */ __name(async (basePath) => { const bothCasesNameMatches = nameMatches.flatMap((match) => [ match, [match[0].toUpperCase(), ...match.slice(1)].join("") ]); const globs = bothCasesNameMatches.flatMap( (match) => extensions.map((extension) => `"${basePath}${sep}*${match}*.${extension}"`) ); try { const command = `git ls-files -- ${globs.join(" ")}`; return await execCommandCountLines(command); } catch { return void 0; } }, "getApplicationFilesCountUncached"); var getApplicationFileCount = /* @__PURE__ */ __name(async (path3) => { return runTelemetryOperation( "applicationFiles", async () => getApplicationFilesCountUncached(path3) ); }, "getApplicationFileCount"); // src/telemetry/get-chromatic-version.ts function getChromaticVersionSpecifier(packageJson) { const dependency = packageJson.dependencies?.chromatic || packageJson.devDependencies?.chromatic || packageJson.peerDependencies?.chromatic; if (dependency) { return dependency; } return packageJson.scripts && Object.values(packageJson.scripts).find((s) => s?.match(/chromatic/)) ? "latest" : void 0; } __name(getChromaticVersionSpecifier, "getChromaticVersionSpecifier"); // src/telemetry/get-framework-info.ts import { normalize } from "node:path"; import { frameworkPackages } from "storybook/internal/common"; // src/telemetry/package-json.ts import { fileURLToPath, pathToFileURL } from "node:url"; var getActualPackageVersions = /* @__PURE__ */ __name(async (packages) => { const packageNames = Object.keys(packages); return Promise.all(packageNames.map(getActualPackageVersion)); }, "getActualPackageVersions"); var getActualPackageVersion = /* @__PURE__ */ __name(async (packageName) => { try { const packageJson = await getActualPackageJson(packageName); return { name: packageJson?.name || packageName, version: packageJson?.version || null }; } catch (err) { return { name: packageName, version: null }; } }, "getActualPackageVersion"); var getActualPackageJson = /* @__PURE__ */ __name(async (packageName) => { try { let resolvedPackageJsonPath = up({ cwd: fileURLToPath(import.meta.resolve(packageName, process.cwd())) }); if (!resolvedPackageJsonPath) { resolvedPackageJsonPath = import.meta.resolve(`${packageName}/package.json`, process.cwd()); } const { default: packageJson } = await import(pathToFileURL(resolvedPackageJsonPath).href, { with: { type: "json" } }); return packageJson; } catch (err) { return void 0; } }, "getActualPackageJson"); // src/telemetry/get-framework-info.ts var knownRenderers = [ "html", "react", "svelte", "vue3", "preact", "server", "vue", "web-components", "angular", "ember" ]; var knownBuilders = ["builder-webpack5", "builder-vite"]; function findMatchingPackage(packageJson, suffixes) { const { name = "", version: version2, dependencies, devDependencies, peerDependencies } = packageJson; const allDependencies = { // We include the framework itself because it may be a renderer too (e.g. angular) [name]: version2, ...dependencies, ...devDependencies, ...peerDependencies }; return suffixes.map((suffix) => `@storybook/${suffix}`).find((pkg) => allDependencies[pkg]); } __name(findMatchingPackage, "findMatchingPackage"); var getFrameworkPackageName = /* @__PURE__ */ __name((packageNameOrPath) => { const normalizedPath = normalize(packageNameOrPath).replace(new RegExp(/\\/, "g"), "/"); const knownFramework = Object.keys(frameworkPackages).find((pkg) => normalizedPath.endsWith(pkg)); return knownFramework || cleanPaths(packageNameOrPath).replace(/.*node_modules[\\/]/, ""); }, "getFrameworkPackageName"); async function getFrameworkInfo(mainConfig) { if (!mainConfig?.framework) { return {}; } const rawName = typeof mainConfig.framework === "string" ? mainConfig.framework : mainConfig.framework?.name; if (!rawName) { return {}; } const frameworkPackageJson = await getActualPackageJson(rawName); if (!frameworkPackageJson) { return {}; } const builder = findMatchingPackage(frameworkPackageJson, knownBuilders); const renderer = findMatchingPackage(frameworkPackageJson, knownRenderers); const sanitizedFrameworkName = getFrameworkPackageName(rawName); const frameworkOptions = typeof mainConfig.framework === "object" ? mainConfig.framework.options : {}; return { framework: { name: sanitizedFrameworkName, options: frameworkOptions }, builder, renderer }; } __name(getFrameworkInfo, "getFrameworkInfo"); // src/telemetry/get-has-router-package.ts var routerPackages = /* @__PURE__ */ new Set([ "react-router", "react-router-dom", "remix", "@tanstack/react-router", "expo-router", "@reach/router", "react-easy-router", "@remix-run/router", "wouter", "wouter-preact", "preact-router", "vue-router", "unplugin-vue-router", "@angular/router", "@solidjs/router", // metaframeworks that imply routing "next", "react-scripts", "gatsby", "nuxt", "@sveltejs/kit" ]); function getHasRouterPackage(packageJson) { return Object.keys(packageJson?.dependencies ?? {}).some( (depName) => routerPackages.has(depName) ); } __name(getHasRouterPackage, "getHasRouterPackage"); // src/telemetry/get-monorepo-type.ts import { existsSync, readFileSync } from "node:fs"; import { join } from "node:path"; import { getProjectRoot as getProjectRoot2 } from "storybook/internal/common"; var monorepoConfigs = { Nx: "nx.json", Turborepo: "turbo.json", Lerna: "lerna.json", Rush: "rush.json", Lage: "lage.config.json" }; var getMonorepoType = /* @__PURE__ */ __name(() => { const keys = Object.keys(monorepoConfigs); const monorepoType = keys.find((monorepo) => { const configFile = join(getProjectRoot2(), monorepoConfigs[monorepo]); return existsSync(configFile); }); if (monorepoType) { return monorepoType; } if (!existsSync(join(getProjectRoot2(), "package.json"))) { return void 0; } const packageJson = JSON.parse( readFileSync(join(getProjectRoot2(), "package.json"), { encoding: "utf8" }) ); if (packageJson?.workspaces) { return "Workspaces"; } return void 0; }, "getMonorepoType"); // ../node_modules/package-manager-detector/dist/commands.mjs function dashDashArg(agent, agentCommand) { return (args) => { if (args.length > 1) { return [agent, agentCommand, args[0], "--", ...args.slice(1)]; } else { return [agent, agentCommand, args[0]]; } }; } __name(dashDashArg, "dashDashArg"); function denoExecute() { return (args) => { return ["deno", "run", `npm:${args[0]}`, ...args.slice(1)]; }; } __name(denoExecute, "denoExecute"); var npm = { "agent": ["npm", 0], "run": dashDashArg("npm", "run"), "install": ["npm", "i", 0], "frozen": ["npm", "ci", 0], "global": ["npm", "i", "-g", 0], "add": ["npm", "i", 0], "upgrade": ["npm", "update", 0], "upgrade-interactive": null, "execute": ["npx", 0], "execute-local": ["npx", 0], "uninstall": ["npm", "uninstall", 0], "global_uninstall": ["npm", "uninstall", "-g", 0] }; var yarn = { "agent": ["yarn", 0], "run": ["yarn", "run", 0], "install": ["yarn", "install", 0], "frozen": ["yarn", "install", "--frozen-lockfile", 0], "global": ["yarn", "global", "add", 0], "add": ["yarn", "add", 0], "upgrade": ["yarn", "upgrade", 0], "upgrade-interactive": ["yarn", "upgrade-interactive", 0], "execute": ["npx", 0], "execute-local": dashDashArg("yarn", "exec"), "uninstall": ["yarn", "remove", 0], "global_uninstall": ["yarn", "global", "remove", 0] }; var yarnBerry = { ...yarn, "frozen": ["yarn", "install", "--immutable", 0], "upgrade": ["yarn", "up", 0], "upgrade-interactive": ["yarn", "up", "-i", 0], "execute": ["yarn", "dlx", 0], "execute-local": ["yarn", "exec", 0], // Yarn 2+ removed 'global', see https://github.com/yarnpkg/berry/issues/821 "global": ["npm", "i", "-g", 0], "global_uninstall": ["npm", "uninstall", "-g", 0] }; var pnpm = { "agent": ["pnpm", 0], "run": ["pnpm", "run", 0], "install": ["pnpm", "i", 0], "frozen": ["pnpm", "i", "--frozen-lockfile", 0], "global": ["pnpm", "add", "-g", 0], "add": ["pnpm", "add", 0], "upgrade": ["pnpm", "update", 0], "upgrade-interactive": ["pnpm", "update", "-i", 0], "execute": ["pnpm", "dlx", 0], "execute-local": ["pnpm", "exec", 0], "uninstall": ["pnpm", "remove", 0], "global_uninstall": ["pnpm", "remove", "--global", 0] }; var bun = { "agent": ["bun", 0], "run": ["bun", "run", 0], "install": ["bun", "install", 0], "frozen": ["bun", "install", "--frozen-lockfile", 0], "global": ["bun", "add", "-g", 0], "add": ["bun", "add", 0], "upgrade": ["bun", "update", 0], "upgrade-interactive": ["bun", "update", 0], "execute": ["bun", "x", 0], "execute-local": ["bun", "x", 0], "uninstall": ["bun", "remove", 0], "global_uninstall": ["bun", "remove", "-g", 0] }; var deno = { "agent": ["deno", 0], "run": ["deno", "task", 0], "install": ["deno", "install", 0], "frozen": ["deno", "install", "--frozen", 0], "global": ["deno", "install", "-g", 0], "add": ["deno", "add", 0], "upgrade": ["deno", "outdated", "--update", 0], "upgrade-interactive": ["deno", "outdated", "--update", 0], "execute": denoExecute(), "execute-local": ["deno", "task", "--eval", 0], "uninstall": ["deno", "remove", 0], "global_uninstall": ["deno", "uninstall", "-g", 0] }; var COMMANDS = { "npm": npm, "yarn": yarn, "yarn@berry": yarnBerry, "pnpm": pnpm, // pnpm v6.x or below "pnpm@6": { ...pnpm, run: dashDashArg("pnpm", "run") }, "bun": bun, "deno": deno }; // ../node_modules/package-manager-detector/dist/constants.mjs var AGENTS = [ "npm", "yarn", "yarn@berry", "pnpm", "pnpm@6", "bun", "deno" ]; var LOCKS = { "bun.lock": "bun", "bun.lockb": "bun", "deno.lock": "deno", "pnpm-lock.yaml": "pnpm", "pnpm-workspace.yaml": "pnpm", "yarn.lock": "yarn", "package-lock.json": "npm", "npm-shrinkwrap.json": "npm" }; var INSTALL_METADATA = { "node_modules/.deno/": "deno", "node_modules/.pnpm/": "pnpm", "node_modules/.yarn-state.yml": "yarn", // yarn v2+ (node-modules) "node_modules/.yarn_integrity": "yarn", // yarn v1 "node_modules/.package-lock.json": "npm", ".pnp.cjs": "yarn", // yarn v3+ (pnp) ".pnp.js": "yarn", // yarn v2 (pnp) "bun.lock": "bun", "bun.lockb": "bun" }; // ../node_modules/package-manager-detector/dist/detect.mjs import fs from "node:fs/promises"; import path2 from "node:path"; import process2 from "node:process"; async function pathExists(path22, type) { try { const stat = await fs.stat(path22); return type === "file" ? stat.isFile() : stat.isDirectory(); } catch { return false; } } __name(pathExists, "pathExists"); function* lookup(cwd = process2.cwd()) { let directory = path2.resolve(cwd); const { root } = path2.parse(directory); while (directory && directory !== root) { yield directory; directory = path2.dirname(directory); } } __name(lookup, "lookup"); async function parsePackageJson(filepath, onUnknown) { return !filepath || !pathExists(filepath, "file") ? null : await handlePackageManager(filepath, onUnknown); } __name(parsePackageJson, "parsePackageJson"); async function detect(options = {}) { const { cwd, strategies = ["lockfile", "packageManager-field", "devEngines-field"], onUnknown } = options; let stopDir; if (typeof options.stopDir === "string") { const resolved = path2.resolve(options.stopDir); stopDir = /* @__PURE__ */ __name((dir) => dir === resolved, "stopDir"); } else { stopDir = options.stopDir; } for (const directory of lookup(cwd)) { for (const strategy of strategies) { switch (strategy) { case "lockfile": { for (const lock of Object.keys(LOCKS)) { if (await pathExists(path2.join(directory, lock), "file")) { const name = LOCKS[lock]; const result = await parsePackageJson(path2.join(directory, "package.json"), onUnknown); if (result) return result; else return { name, agent: name }; } } break; } case "packageManager-field": case "devEngines-field": { const result = await parsePackageJson(path2.join(directory, "package.json"), onUnknown); if (result) return result; break; } case "install-metadata": { for (const metadata of Object.keys(INSTALL_METADATA)) { const fileOrDir = metadata.endsWith("/") ? "dir" : "file"; if (await pathExists(path2.join(directory, metadata), fileOrDir)) { const name = INSTALL_METADATA[metadata]; const agent = name === "yarn" ? isMetadataYarnClassic(metadata) ? "yarn" : "yarn@berry" : name; return { name, agent }; } } break; } } } if (stopDir?.(directory)) break; } return null; } __name(detect, "detect"); function getNameAndVer(pkg) { const handelVer = /* @__PURE__ */ __name((version2) => version2?.match(/\d+(\.\d+){0,2}/)?.[0] ?? version2, "handelVer"); if (typeof pkg.packageManager === "string") { const [name, ver] = pkg.packageManager.replace(/^\^/, "").split("@"); return { name, ver: handelVer(ver) }; } if (typeof pkg.devEngines?.packageManager?.name === "string") { return { name: pkg.devEngines.packageManager.name, ver: handelVer(pkg.devEngines.packageManager.version) }; } return void 0; } __name(getNameAndVer, "getNameAndVer"); async function handlePackageManager(filepath, onUnknown) { try { const pkg = JSON.parse(await fs.readFile(filepath, "utf8")); let agent; const nameAndVer = getNameAndVer(pkg); if (nameAndVer) { const name = nameAndVer.name; const ver = nameAndVer.ver; let version2 = ver; if (name === "yarn" && ver && Number.parseInt(ver) > 1) { agent = "yarn@berry"; version2 = "berry"; return { name, agent, version: version2 }; } else if (name === "pnpm" && ver && Number.parseInt(ver) < 7) { agent = "pnpm@6"; return { name, agent, version: version2 }; } else if (AGENTS.includes(name)) { agent = name; return { name, agent, version: version2 }; } else { return onUnknown?.(pkg.packageManager) ?? null; } } } catch { } return null; } __name(handlePackageManager, "handlePackageManager"); function isMetadataYarnClassic(metadataPath) { return metadataPath.endsWith(".yarn_integrity"); } __name(isMetadataYarnClassic, "isMetadataYarnClassic"); // src/telemetry/get-package-manager-info.ts var getPackageManagerInfo = /* @__PURE__ */ __name(async () => { const packageManagerType = await detect({ cwd: getProjectRoot() }); if (!packageManagerType) { return void 0; } let nodeLinker = "node_modules"; if (packageManagerType.name === "yarn") { try { const { stdout } = await execaCommand("yarn config get nodeLinker", { cwd: getProjectRoot() }); nodeLinker = stdout.trim(); } catch (e) { } } if (packageManagerType.name === "pnpm") { try { const { stdout } = await execaCommand("pnpm config get nodeLinker", { cwd: getProjectRoot() }); nodeLinker = stdout.trim() ?? "isolated"; } catch (e) { } } return { type: packageManagerType.name, version: packageManagerType.version, agent: packageManagerType.agent, nodeLinker }; }, "getPackageManagerInfo"); // src/telemetry/get-portable-stories-usage.ts var getPortableStoriesFileCountUncached = /* @__PURE__ */ __name(async (path3) => { try { const command = `git grep -l composeStor` + (path3 ? ` -- ${path3}` : ""); return await execCommandCountLines(command); } catch (err) { return err.exitCode === 1 ? 0 : void 0; } }, "getPortableStoriesFileCountUncached"); var getPortableStoriesFileCount = /* @__PURE__ */ __name(async (path3) => { return runTelemetryOperation( "portableStories", async () => getPortableStoriesFileCountUncached(path3) ); }, "getPortableStoriesFileCount"); // src/telemetry/storybook-metadata.ts var metaFrameworks = { next: "Next", "react-scripts": "CRA", gatsby: "Gatsby", "@nuxtjs/storybook": "nuxt", "@nrwl/storybook": "nx", "@vue/cli-service": "vue-cli", "@sveltejs/kit": "sveltekit", "@tanstack/react-router": "tanstack-react", "@react-router/dev": "react-router", "@remix-run/dev": "remix" }; var sanitizeAddonName = /* @__PURE__ */ __name((name) => { return cleanPaths(name).replace(/\/dist\/.*/, "").replace(/\.[mc]?[tj]?s[x]?$/, "").replace(/\/register$/, "").replace(/\/manager$/, "").replace(/\/preset$/, ""); }, "sanitizeAddonName"); var computeStorybookMetadata = /* @__PURE__ */ __name(async ({ packageJsonPath, packageJson, mainConfig, configDir }) => { const settings = isCI() ? void 0 : await globalSettings(); const metadata = { generatedAt: (/* @__PURE__ */ new Date()).getTime(), userSince: settings?.value.userSince, hasCustomBabel: false, hasCustomWebpack: false, hasStaticDirs: false, hasStorybookEslint: false, refCount: 0 }; const allDependencies = { ...packageJson?.dependencies, ...packageJson?.devDependencies, ...packageJson?.peerDependencies }; const metaFramework = Object.keys(allDependencies).find((dep) => !!metaFrameworks[dep]); if (metaFramework) { const { version: version2 } = await getActualPackageVersion(metaFramework); metadata.metaFramework = { name: metaFrameworks[metaFramework], packageName: metaFramework, version: version2 || "unknown" }; } const testPackages = [ "playwright", "vitest", "jest", "cypress", "nightwatch", "webdriver", "@web/test-runner", "puppeteer", "karma", "jasmine", "chai", "testing-library", "@ngneat/spectator", "wdio", "msw", "miragejs", "sinon", "chromatic" ]; const testPackageDeps = Object.keys(allDependencies).filter( (dep) => testPackages.find((pkg) => dep.includes(pkg)) ); metadata.testPackages = Object.fromEntries( await Promise.all( testPackageDeps.map(async (dep) => [dep, (await getActualPackageVersion(dep))?.version]) ) ); metadata.hasRouterPackage = getHasRouterPackage(packageJson); const monorepoType = getMonorepoType(); if (monorepoType) { metadata.monorepo = monorepoType; } metadata.packageManager = await getPackageManagerInfo(); const language = allDependencies.typescript ? "typescript" : "javascript"; if (!mainConfig) { return { ...metadata, storybookVersionSpecifier: versions.storybook, language }; } metadata.hasCustomBabel = !!mainConfig.babel; metadata.hasCustomWebpack = !!mainConfig.webpackFinal; metadata.hasStaticDirs = !!mainConfig.staticDirs; if (typeof mainConfig.typescript === "object") { metadata.typescriptOptions = mainConfig.typescript; } const frameworkInfo = await getFrameworkInfo(mainConfig); if (typeof mainConfig.refs === "object") { metadata.refCount = Object.keys(mainConfig.refs).length; } if (typeof mainConfig.features === "object") { metadata.features = mainConfig.features; } const addons = {}; if (mainConfig.addons) { mainConfig.addons.forEach((addon) => { let addonName; let options; if (typeof addon === "string") { addonName = sanitizeAddonName(addon); } else { if (addon.name.includes("addon-essentials")) { options = addon.options; } addonName = sanitizeAddonName(addon.name); } addons[addonName] = { options, version: void 0 }; }); } const chromaticVersionSpecifier = getChromaticVersionSpecifier(packageJson); if (chromaticVersionSpecifier) { addons.chromatic = { version: void 0, versionSpecifier: chromaticVersionSpecifier, options: void 0 }; } const addonVersions = await getActualPackageVersions(addons); addonVersions.forEach(({ name, version: version2 }) => { addons[name] = addons[name] || { name, version: version2 }; addons[name].version = version2 || void 0; }); const addonNames = Object.keys(addons); const storybookPackages = Object.keys(allDependencies).filter((dep) => dep.includes("storybook") && !addonNames.includes(dep)).reduce((acc, dep) => { return { ...acc, [dep]: { version: void 0 } }; }, {}); const storybookPackageVersions = await getActualPackageVersions(storybookPackages); storybookPackageVersions.forEach(({ name, version: version2 }) => { storybookPackages[name] = storybookPackages[name] || { name, version: version2 }; storybookPackages[name].version = version2 || void 0; }); const hasStorybookEslint = !!allDependencies["eslint-plugin-storybook"]; const storybookInfo = await getStorybookInfo(configDir); try { const { previewConfigPath: previewConfig } = storybookInfo; if (previewConfig) { const config = await readConfig(previewConfig); const usesGlobals = !!(config.getFieldNode(["globals"]) || config.getFieldNode(["globalTypes"])); metadata.preview = { ...metadata.preview, usesGlobals }; } } catch (e) { } const portableStoriesFileCount = await getPortableStoriesFileCount(); const applicationFileCount = await getApplicationFileCount(dirname(packageJsonPath)); return { ...metadata, ...frameworkInfo, portableStoriesFileCount, applicationFileCount, storybookVersion: version, storybookVersionSpecifier: storybookInfo.version, language, storybookPackages, addons, hasStorybookEslint }; }, "computeStorybookMetadata"); async function getPackageJsonDetails() { const packageJsonPath = up(); if (packageJsonPath) { return { packageJsonPath, packageJson: JSON.parse(await readFile(packageJsonPath, "utf8")) }; } return { packageJsonPath: process.cwd(), packageJson: {} }; } __name(getPackageJsonDetails, "getPackageJsonDetails"); var cachedMetadata; var getStorybookMetadata = /* @__PURE__ */ __name(async (_configDir) => { if (cachedMetadata) { return cachedMetadata; } const { packageJson, packageJsonPath } = await getPackageJsonDetails(); const configDir = (_configDir || getStorybookConfiguration( String(packageJson?.scripts?.storybook || ""), "-c", "--config-dir" )) ?? ".storybook"; const mainConfig = await loadMainConfig({ configDir }).catch(() => void 0); cachedMetadata = await computeStorybookMetadata({ mainConfig, packageJson, packageJsonPath, configDir }); return cachedMetadata; }, "getStorybookMetadata"); // src/telemetry/telemetry.ts var import_fetch_retry = __toESM(require_fetch_retry(), 1); import { readFileSync as readFileSync2 } from "node:fs"; import * as os from "node:os"; import { join as join2 } from "node:path"; import { isCI as isCI2 } from "storybook/internal/common"; // src/telemetry/anonymous-id.ts import { relative } from "node:path"; import { getProjectRoot as getProjectRoot3 } from "storybook/internal/common"; import { execSync } from "child_process"; // src/telemetry/one-way-hash.ts import { createHash } from "crypto"; var oneWayHash = /* @__PURE__ */ __name((payload) => { const hash = createHash("sha256"); hash.update("storybook-telemetry-salt"); hash.update(payload); return hash.digest("hex"); }, "oneWayHash"); // src/telemetry/anonymous-id.ts function normalizeGitUrl(rawUrl) { const urlWithoutHash = rawUrl.trim().replace(/#.*$/, ""); const urlWithoutUser = urlWithoutHash.replace(/^.*@/, ""); const urlWithoutScheme = urlWithoutUser.replace(/^.*\/\//, ""); const urlWithExtension = urlWithoutScheme.endsWith(".git") ? urlWithoutScheme : `${urlWithoutScheme}.git`; return urlWithExtension.replace(":", "/"); } __name(normalizeGitUrl, "normalizeGitUrl"); function unhashedProjectId(remoteUrl, projectRootPath) { return `${normalizeGitUrl(remoteUrl)}${slash(projectRootPath)}`; } __name(unhashedProjectId, "unhashedProjectId"); var anonymousProjectId; var getAnonymousProjectId = /* @__PURE__ */ __name(() => { if (anonymousProjectId) { return anonymousProjectId; } try { const projectRootPath = relative(getProjectRoot3(), process.cwd()); const originBuffer = execSync(`git config --local --get remote.origin.url`, { timeout: 1e3, stdio: `pipe` }); anonymousProjectId = oneWayHash(unhashedProjectId(String(originBuffer), projectRootPath)); } catch (_) { } return anonymousProjectId; }, "getAnonymousProjectId"); // src/telemetry/fetch.ts var fetch = global.fetch; // src/telemetry/telemetry.ts var retryingFetch = (0, import_fetch_retry.default)(fetch); var URL = process.env.STORYBOOK_TELEMETRY_URL || "https://storybook.js.org/event-log"; var tasks = []; var addToGlobalContext = /* @__PURE__ */ __name((key, value) => { globalContext[key] = value; }, "addToGlobalContext"); var getOperatingSystem = /* @__PURE__ */ __name(() => { try { const platform2 = os.platform(); if (platform2 === "win32") { return "Windows"; } if (platform2 === "darwin") { return "macOS"; } if (platform2 === "linux") { return "Linux"; } return `Other: ${platform2}`; } catch (_err) { return "Unknown"; } }, "getOperatingSystem"); var globalContext = { inCI: isCI2(), isTTY: process.stdout.isTTY, platform: getOperatingSystem(), nodeVersion: process.versions.node, storybookVersion: getVersionNumber() }; var prepareRequest = /* @__PURE__ */ __name(async (data, context, options) => { const { eventType, payload, metadata, ...rest } = data; const sessionId = await getSessionId(); const eventId = nanoid(); const body = { ...rest, eventType, eventId, sessionId, metadata, payload, context }; return retryingFetch(URL, { method: "post", body: JSON.stringify(body), headers: { "Content-Type": "application/json" }, retries: 3, retryOn: [503, 504], retryDelay: /* @__PURE__ */ __name((attempt) => 2 ** attempt * (typeof options?.retryDelay === "number" && !Number.isNaN(options?.retryDelay) ? options.retryDelay : 1e3), "retryDelay") }); }, "prepareRequest"); function getVersionNumber() { try { return JSON.parse(readFileSync2(join2(resolvePackageDir("storybook"), "package.json"), "utf8")).version; } catch (e) { return version; } } __name(getVersionNumber, "getVersionNumber"); async function sendTelemetry(data, options = { retryDelay: 1e3, immediate: false }) { const { eventType, payload, metadata, ...rest } = data; const context = options.stripMetadata ? globalContext : { ...globalContext, anonymousId: getAnonymousProjectId() }; let request; try { request = prepareRequest(data, context, options); tasks.push(request); const sessionId = await getSessionId(); const eventId = nanoid(); const body = { ...rest, eventType, eventId, sessionId, metadata, payload, context }; const waitFor = options.immediate ? tasks : [request]; await Promise.all([...waitFor, set(eventType, body)]); } catch (err) { } finally { tasks = tasks.filter((task) => task !== request); } } __name(sendTelemetry, "sendTelemetry"); // src/telemetry/index.ts var isExampleStoryId = /* @__PURE__ */ __name((storyId) => storyId.startsWith("example-button--") || storyId.startsWith("example-header--") || storyId.startsWith("example-page--"), "isExampleStoryId"); var telemetry = /* @__PURE__ */ __name(async (eventType, payload = {}, options = {}) => { if (eventType !== "boot" && options.notify !== false) { await notify(); } const telemetryData = { eventType, payload }; try { if (!options?.stripMetadata) { telemetryData.metadata = await getStorybookMetadata(options?.configDir); } } catch (error) { payload.metadataErrorMessage = sanitizeError(error).message; if (options?.enableCrashReports) { payload.metadataError = sanitizeError(error); } } finally { const { error } = payload; if (error) { payload.error = sanitizeError(error); } if (!payload.error || options?.enableCrashReports) { if (process.env?.STORYBOOK_TELEMETRY_DEBUG) { logger2.info("\n[telemetry]"); logger2.info(JSON.stringify(telemetryData, null, 2)); } await sendTelemetry(telemetryData, options); } } }, "telemetry"); export { removeAnsiEscapeCodes, cleanPaths, sanitizeError, metaFrameworks, sanitizeAddonName, computeStorybookMetadata, getStorybookMetadata, oneWayHash, addToGlobalContext, isExampleStoryId, telemetry };