import CJS_COMPAT_NODE_URL_bqgqh4d46dd from 'node:url';
import CJS_COMPAT_NODE_PATH_bqgqh4d46dd from 'node:path';
import CJS_COMPAT_NODE_MODULE_bqgqh4d46dd from "node:module";

var __filename = CJS_COMPAT_NODE_URL_bqgqh4d46dd.fileURLToPath(import.meta.url);
var __dirname = CJS_COMPAT_NODE_PATH_bqgqh4d46dd.dirname(__filename);
var require = CJS_COMPAT_NODE_MODULE_bqgqh4d46dd.createRequire(import.meta.url);

// ------------------------------------------------------------
// end of CJS compatibility banner, injected by Storybook's esbuild configuration
// ------------------------------------------------------------
import {
  any,
  up2 as up
} from "./chunk-5KDXQR2J.js";
import {
  invariant
} from "./chunk-5X7FGASE.js";
import {
  resolvePackageDir
} from "./chunk-TSKLBMF3.js";
import {
  require_prompts
} from "./chunk-NYXHMPY4.js";
import {
  require_picocolors
} from "./chunk-2JHIUWIN.js";
import {
  __name,
  __toESM
} from "./chunk-T7KB265F.js";

// src/cli/project_types.ts
import { minVersion, validRange } from "semver";
function eqMajor(versionRange, major) {
  if (validRange(versionRange)) {
    return minVersion(versionRange)?.major === major;
  }
  return false;
}
__name(eqMajor, "eqMajor");
var externalFrameworks = [
  { name: "qwik", packageName: "storybook-framework-qwik" },
  {
    name: "solid",
    packageName: "storybook-solidjs-vite",
    frameworks: ["storybook-solidjs-vite"],
    renderer: "storybook-solidjs-vite"
  },
  {
    name: "nuxt",
    packageName: "@storybook-vue/nuxt",
    frameworks: ["@storybook-vue/nuxt"],
    renderer: "@storybook/vue3"
  }
];
var SUPPORTED_RENDERERS = [
  "react",
  "react-native",
  "vue3",
  "angular",
  "ember",
  "preact",
  "svelte",
  "qwik",
  "solid"
];
var ProjectType = /* @__PURE__ */ ((ProjectType2) => {
  ProjectType2["UNDETECTED"] = "UNDETECTED";
  ProjectType2["UNSUPPORTED"] = "UNSUPPORTED";
  ProjectType2["REACT"] = "REACT";
  ProjectType2["REACT_SCRIPTS"] = "REACT_SCRIPTS";
  ProjectType2["REACT_NATIVE"] = "REACT_NATIVE";
  ProjectType2["REACT_NATIVE_WEB"] = "REACT_NATIVE_WEB";
  ProjectType2["REACT_NATIVE_AND_RNW"] = "REACT_NATIVE_AND_RNW";
  ProjectType2["REACT_PROJECT"] = "REACT_PROJECT";
  ProjectType2["WEBPACK_REACT"] = "WEBPACK_REACT";
  ProjectType2["NEXTJS"] = "NEXTJS";
  ProjectType2["VUE3"] = "VUE3";
  ProjectType2["NUXT"] = "NUXT";
  ProjectType2["ANGULAR"] = "ANGULAR";
  ProjectType2["EMBER"] = "EMBER";
  ProjectType2["WEB_COMPONENTS"] = "WEB_COMPONENTS";
  ProjectType2["HTML"] = "HTML";
  ProjectType2["QWIK"] = "QWIK";
  ProjectType2["PREACT"] = "PREACT";
  ProjectType2["SVELTE"] = "SVELTE";
  ProjectType2["SVELTEKIT"] = "SVELTEKIT";
  ProjectType2["SERVER"] = "SERVER";
  ProjectType2["NX"] = "NX";
  ProjectType2["SOLID"] = "SOLID";
  return ProjectType2;
})(ProjectType || {});
var CoreBuilder = /* @__PURE__ */ ((CoreBuilder2) => {
  CoreBuilder2["Webpack5"] = "webpack5";
  CoreBuilder2["Vite"] = "vite";
  return CoreBuilder2;
})(CoreBuilder || {});
var CoreWebpackCompilers = /* @__PURE__ */ ((CoreWebpackCompilers2) => {
  CoreWebpackCompilers2["Babel"] = "babel";
  CoreWebpackCompilers2["SWC"] = "swc";
  return CoreWebpackCompilers2;
})(CoreWebpackCompilers || {});
var CommunityBuilder = /* @__PURE__ */ ((CommunityBuilder2) => {
  CommunityBuilder2["Rsbuild"] = "rsbuild";
  return CommunityBuilder2;
})(CommunityBuilder || {});
var compilerNameToCoreCompiler = {
  "@storybook/addon-webpack5-compiler-babel": "babel" /* Babel */,
  "@storybook/addon-webpack5-compiler-swc": "swc" /* SWC */
};
var builderNameToCoreBuilder = {
  "@storybook/builder-webpack5": "webpack5" /* Webpack5 */,
  "@storybook/builder-vite": "vite" /* Vite */
};
var SupportedLanguage = /* @__PURE__ */ ((SupportedLanguage2) => {
  SupportedLanguage2["JAVASCRIPT"] = "javascript";
  SupportedLanguage2["TYPESCRIPT"] = "typescript";
  return SupportedLanguage2;
})(SupportedLanguage || {});
var supportedTemplates = [
  {
    preset: "NUXT" /* NUXT */,
    dependencies: ["nuxt"],
    matcherFunction: /* @__PURE__ */ __name(({ dependencies }) => {
      return dependencies?.every(Boolean) ?? true;
    }, "matcherFunction")
  },
  {
    preset: "VUE3" /* VUE3 */,
    dependencies: {
      // This Vue template works with Vue 3
      vue: /* @__PURE__ */ __name((versionRange) => versionRange === "next" || eqMajor(versionRange, 3), "vue")
    },
    matcherFunction: /* @__PURE__ */ __name(({ dependencies }) => {
      return dependencies?.some(Boolean) ?? false;
    }, "matcherFunction")
  },
  {
    preset: "EMBER" /* EMBER */,
    dependencies: ["ember-cli"],
    matcherFunction: /* @__PURE__ */ __name(({ dependencies }) => {
      return dependencies?.every(Boolean) ?? true;
    }, "matcherFunction")
  },
  {
    preset: "NEXTJS" /* NEXTJS */,
    dependencies: ["next"],
    matcherFunction: /* @__PURE__ */ __name(({ dependencies }) => {
      return dependencies?.every(Boolean) ?? true;
    }, "matcherFunction")
  },
  {
    preset: "QWIK" /* QWIK */,
    dependencies: ["@builder.io/qwik"],
    matcherFunction: /* @__PURE__ */ __name(({ dependencies }) => {
      return dependencies?.every(Boolean) ?? true;
    }, "matcherFunction")
  },
  {
    preset: "REACT_PROJECT" /* REACT_PROJECT */,
    peerDependencies: ["react"],
    matcherFunction: /* @__PURE__ */ __name(({ peerDependencies }) => {
      return peerDependencies?.every(Boolean) ?? true;
    }, "matcherFunction")
  },
  {
    preset: "REACT_NATIVE" /* REACT_NATIVE */,
    dependencies: ["react-native", "react-native-scripts"],
    matcherFunction: /* @__PURE__ */ __name(({ dependencies }) => {
      return dependencies?.some(Boolean) ?? false;
    }, "matcherFunction")
  },
  {
    preset: "REACT_SCRIPTS" /* REACT_SCRIPTS */,
    // For projects using a custom/forked `react-scripts` package.
    files: ["/node_modules/.bin/react-scripts"],
    // For standard CRA projects
    dependencies: ["react-scripts"],
    matcherFunction: /* @__PURE__ */ __name(({ dependencies, files }) => {
      return (dependencies?.every(Boolean) || files?.every(Boolean)) ?? false;
    }, "matcherFunction")
  },
  {
    preset: "ANGULAR" /* ANGULAR */,
    dependencies: ["@angular/core"],
    matcherFunction: /* @__PURE__ */ __name(({ dependencies }) => {
      return dependencies?.every(Boolean) ?? true;
    }, "matcherFunction")
  },
  {
    preset: "WEB_COMPONENTS" /* WEB_COMPONENTS */,
    dependencies: ["lit-element", "lit-html", "lit"],
    matcherFunction: /* @__PURE__ */ __name(({ dependencies }) => {
      return dependencies?.some(Boolean) ?? false;
    }, "matcherFunction")
  },
  {
    preset: "PREACT" /* PREACT */,
    dependencies: ["preact"],
    matcherFunction: /* @__PURE__ */ __name(({ dependencies }) => {
      return dependencies?.every(Boolean) ?? true;
    }, "matcherFunction")
  },
  {
    // TODO: This only works because it is before the SVELTE template. could be more explicit
    preset: "SVELTEKIT" /* SVELTEKIT */,
    dependencies: ["@sveltejs/kit"],
    matcherFunction: /* @__PURE__ */ __name(({ dependencies }) => {
      return dependencies?.every(Boolean) ?? true;
    }, "matcherFunction")
  },
  {
    preset: "SVELTE" /* SVELTE */,
    dependencies: ["svelte"],
    matcherFunction: /* @__PURE__ */ __name(({ dependencies }) => {
      return dependencies?.every(Boolean) ?? true;
    }, "matcherFunction")
  },
  {
    preset: "SOLID" /* SOLID */,
    dependencies: ["solid-js"],
    matcherFunction: /* @__PURE__ */ __name(({ dependencies }) => {
      return dependencies?.every(Boolean) ?? true;
    }, "matcherFunction")
  },
  // DO NOT MOVE ANY TEMPLATES BELOW THIS LINE
  // React is part of every Template, after Storybook is initialized once
  {
    preset: "WEBPACK_REACT" /* WEBPACK_REACT */,
    dependencies: ["react", "webpack"],
    matcherFunction: /* @__PURE__ */ __name(({ dependencies }) => {
      return dependencies?.every(Boolean) ?? true;
    }, "matcherFunction")
  },
  {
    preset: "REACT" /* REACT */,
    dependencies: ["react"],
    matcherFunction: /* @__PURE__ */ __name(({ dependencies }) => {
      return dependencies?.every(Boolean) ?? true;
    }, "matcherFunction")
  }
];
var unsupportedTemplate = {
  preset: "UNSUPPORTED" /* UNSUPPORTED */,
  dependencies: {},
  matcherFunction: /* @__PURE__ */ __name(({ dependencies }) => {
    return dependencies?.some(Boolean) ?? false;
  }, "matcherFunction")
};
var notInstallableProjectTypes = [
  "UNDETECTED" /* UNDETECTED */,
  "UNSUPPORTED" /* UNSUPPORTED */,
  "NX" /* NX */
];
var installableProjectTypes = Object.values(ProjectType).filter((type) => !notInstallableProjectTypes.includes(type)).map((type) => type.toLowerCase());

// src/cli/dirs.ts
import { join as join2 } from "node:path";
import { Readable as Readable2 } from "node:stream";
import { pipeline as pipeline2 } from "node:stream/promises";
import { createGunzip } from "node:zlib";
import { temporaryDirectory, versions } from "storybook/internal/common";

// ../node_modules/get-npm-tarball-url/lib/index.mjs
function src_default(pkgName, pkgVersion, opts) {
  let registry;
  if (opts == null ? void 0 : opts.registry) {
    registry = opts.registry.endsWith("/") ? opts.registry : `${opts.registry}/`;
  } else {
    registry = "https://registry.npmjs.org/";
  }
  const scopelessName = getScopelessName(pkgName);
  return `${registry}${pkgName}/-/${scopelessName}-${removeBuildMetadataFromVersion(pkgVersion)}.tgz`;
}
__name(src_default, "src_default");
function removeBuildMetadataFromVersion(version) {
  const plusPos = version.indexOf("+");
  if (plusPos === -1)
    return version;
  return version.substring(0, plusPos);
}
__name(removeBuildMetadataFromVersion, "removeBuildMetadataFromVersion");
function getScopelessName(name) {
  if (name[0] !== "@") {
    return name;
  }
  return name.split("/")[1];
}
__name(getScopelessName, "getScopelessName");

// ../node_modules/modern-tar/dist/unpacker-BKKRRs7i.js
var BLOCK_SIZE = 512;
var BLOCK_SIZE_MASK = 511;
var USTAR_NAME_OFFSET = 0;
var USTAR_NAME_SIZE = 100;
var USTAR_MODE_OFFSET = 100;
var USTAR_MODE_SIZE = 8;
var USTAR_UID_OFFSET = 108;
var USTAR_UID_SIZE = 8;
var USTAR_GID_OFFSET = 116;
var USTAR_GID_SIZE = 8;
var USTAR_SIZE_OFFSET = 124;
var USTAR_SIZE_SIZE = 12;
var USTAR_MTIME_OFFSET = 136;
var USTAR_MTIME_SIZE = 12;
var USTAR_CHECKSUM_OFFSET = 148;
var USTAR_CHECKSUM_SIZE = 8;
var USTAR_TYPEFLAG_OFFSET = 156;
var USTAR_TYPEFLAG_SIZE = 1;
var USTAR_LINKNAME_OFFSET = 157;
var USTAR_LINKNAME_SIZE = 100;
var USTAR_MAGIC_OFFSET = 257;
var USTAR_MAGIC_SIZE = 6;
var USTAR_UNAME_OFFSET = 265;
var USTAR_UNAME_SIZE = 32;
var USTAR_GNAME_OFFSET = 297;
var USTAR_GNAME_SIZE = 32;
var USTAR_PREFIX_OFFSET = 345;
var USTAR_PREFIX_SIZE = 155;
var FLAGTYPE = {
  "0": "file",
  "1": "link",
  "2": "symlink",
  "3": "character-device",
  "4": "block-device",
  "5": "directory",
  "6": "fifo",
  x: "pax-header",
  g: "pax-global-header",
  L: "gnu-long-name",
  K: "gnu-long-link-name"
};
var ZERO_BLOCK = new Uint8Array(BLOCK_SIZE);
var encoder = new TextEncoder();
var decoder = new TextDecoder();
function readString(view, offset, size) {
  const end = view.indexOf(0, offset);
  const sliceEnd = end === -1 || end > offset + size ? offset + size : end;
  return decoder.decode(view.subarray(offset, sliceEnd));
}
__name(readString, "readString");
function readOctal(view, offset, size) {
  let value = 0;
  const end = offset + size;
  for (let i = offset; i < end; i++) {
    const charCode = view[i];
    if (charCode === 0) break;
    if (charCode === 32) continue;
    value = (value << 3) + (charCode - 48);
  }
  return value;
}
__name(readOctal, "readOctal");
function readNumeric(view, offset, size) {
  if (view[offset] & 128) {
    let result = 0;
    result = view[offset] & 127;
    for (let i = 1; i < size; i++) result = result * 256 + view[offset + i];
    if (!Number.isSafeInteger(result)) throw new Error("TAR number too large");
    return result;
  }
  return readOctal(view, offset, size);
}
__name(readNumeric, "readNumeric");
var CHECKSUM_SPACE = 32;
function validateChecksum(block) {
  const stored = readOctal(block, USTAR_CHECKSUM_OFFSET, USTAR_CHECKSUM_SIZE);
  let sum = 0;
  for (let i = 0; i < block.length; i++) if (i >= USTAR_CHECKSUM_OFFSET && i < USTAR_CHECKSUM_OFFSET + USTAR_CHECKSUM_SIZE) sum += CHECKSUM_SPACE;
  else sum += block[i];
  return stored === sum;
}
__name(validateChecksum, "validateChecksum");
function parseUstarHeader(block, strict) {
  if (strict && !validateChecksum(block)) throw new Error("Invalid tar header checksum.");
  const typeflag = readString(block, USTAR_TYPEFLAG_OFFSET, USTAR_TYPEFLAG_SIZE);
  const header = {
    name: readString(block, USTAR_NAME_OFFSET, USTAR_NAME_SIZE),
    mode: readOctal(block, USTAR_MODE_OFFSET, USTAR_MODE_SIZE),
    uid: readNumeric(block, USTAR_UID_OFFSET, USTAR_UID_SIZE),
    gid: readNumeric(block, USTAR_GID_OFFSET, USTAR_GID_SIZE),
    size: readNumeric(block, USTAR_SIZE_OFFSET, USTAR_SIZE_SIZE),
    mtime: new Date(readNumeric(block, USTAR_MTIME_OFFSET, USTAR_MTIME_SIZE) * 1e3),
    type: FLAGTYPE[typeflag] || "file",
    linkname: readString(block, USTAR_LINKNAME_OFFSET, USTAR_LINKNAME_SIZE)
  };
  const magic = readString(block, USTAR_MAGIC_OFFSET, USTAR_MAGIC_SIZE);
  if (magic.trim() === "ustar") {
    header.uname = readString(block, USTAR_UNAME_OFFSET, USTAR_UNAME_SIZE);
    header.gname = readString(block, USTAR_GNAME_OFFSET, USTAR_GNAME_SIZE);
  }
  if (magic === "ustar") header.prefix = readString(block, USTAR_PREFIX_OFFSET, USTAR_PREFIX_SIZE);
  return header;
}
__name(parseUstarHeader, "parseUstarHeader");
var PAX_MAPPING = {
  path: ["name", (v) => v],
  linkpath: ["linkname", (v) => v],
  size: ["size", (v) => parseInt(v, 10)],
  mtime: ["mtime", parseFloat],
  uid: ["uid", (v) => parseInt(v, 10)],
  gid: ["gid", (v) => parseInt(v, 10)],
  uname: ["uname", (v) => v],
  gname: ["gname", (v) => v]
};
function parsePax(buffer) {
  const decoder$1 = new TextDecoder("utf-8");
  const overrides = {};
  const pax = {};
  let offset = 0;
  while (offset < buffer.length) {
    const spaceIndex = buffer.indexOf(32, offset);
    if (spaceIndex === -1) break;
    const length = parseInt(decoder$1.decode(buffer.subarray(offset, spaceIndex)), 10);
    if (Number.isNaN(length) || length === 0) break;
    const recordEnd = offset + length;
    const [key, value] = decoder$1.decode(buffer.subarray(spaceIndex + 1, recordEnd - 1)).split("=", 2);
    if (key && value !== void 0) {
      pax[key] = value;
      const mapping = PAX_MAPPING[key];
      if (mapping) {
        const [targetKey, parser] = mapping;
        const parsedValue = parser(value);
        if (typeof parsedValue === "string" || !Number.isNaN(parsedValue)) overrides[targetKey] = parsedValue;
      }
    }
    offset = recordEnd;
  }
  if (Object.keys(pax).length > 0) overrides.pax = pax;
  return overrides;
}
__name(parsePax, "parsePax");
function applyOverrides(header, overrides) {
  if (overrides.name !== void 0) header.name = overrides.name;
  if (overrides.linkname !== void 0) header.linkname = overrides.linkname;
  if (overrides.size !== void 0) header.size = overrides.size;
  if (overrides.mtime !== void 0) header.mtime = new Date(overrides.mtime * 1e3);
  if (overrides.uid !== void 0) header.uid = overrides.uid;
  if (overrides.gid !== void 0) header.gid = overrides.gid;
  if (overrides.uname !== void 0) header.uname = overrides.uname;
  if (overrides.gname !== void 0) header.gname = overrides.gname;
  if (overrides.pax) header.pax = Object.assign({}, header.pax ?? {}, overrides.pax);
}
__name(applyOverrides, "applyOverrides");
function getMetaParser(type) {
  switch (type) {
    case "pax-global-header":
    case "pax-header":
      return parsePax;
    case "gnu-long-name":
      return (data) => ({ name: readString(data, 0, data.length) });
    case "gnu-long-link-name":
      return (data) => ({ linkname: readString(data, 0, data.length) });
    default:
      return;
  }
}
__name(getMetaParser, "getMetaParser");
var EOF_BUFFER = new Uint8Array(BLOCK_SIZE * 2);
function transformHeader(header, options) {
  const { strip, filter, map } = options;
  if (!strip && !filter && !map) return header;
  const h = { ...header };
  if (strip && strip > 0) {
    const components = h.name.split("/").filter(Boolean);
    if (strip >= components.length) return null;
    const newName = components.slice(strip).join("/");
    h.name = h.type === "directory" && !newName.endsWith("/") ? `${newName}/` : newName;
    if (h.linkname?.startsWith("/")) {
      const linkComponents = h.linkname.split("/").filter(Boolean);
      h.linkname = strip >= linkComponents.length ? "/" : `/${linkComponents.slice(strip).join("/")}`;
    }
  }
  if (filter?.(h) === false) return null;
  const result = map ? map(h) : h;
  if (result && (!result.name || !result.name.trim() || result.name === "." || result.name === "/")) return null;
  return result;
}
__name(transformHeader, "transformHeader");
var STATE_HEADER = 0;
var STATE_BODY = 1;
var STATE_PADDING = 2;
var STATE_AWAIT_EOF = 3;
function createTarUnpacker(handler, options = {}) {
  const strict = options.strict ?? false;
  const chunkQueue = [];
  let totalAvailable = 0;
  let state = STATE_HEADER;
  let waitingForData = false;
  let currentEntry = null;
  const paxGlobals = {};
  let nextEntryOverrides = {};
  function consume(size, callback) {
    let remaining = Math.min(size, totalAvailable);
    const initialRemaining = remaining;
    while (remaining > 0 && chunkQueue.length > 0) {
      const chunkNode = chunkQueue[0];
      const available = chunkNode.data.length - chunkNode.consumed;
      const toProcess = Math.min(remaining, available);
      if (callback) callback(chunkNode.data.subarray(chunkNode.consumed, chunkNode.consumed + toProcess));
      chunkNode.consumed += toProcess;
      remaining -= toProcess;
      if (chunkNode.consumed >= chunkNode.data.length) chunkQueue.shift();
    }
    totalAvailable -= initialRemaining - remaining;
    return initialRemaining - remaining;
  }
  __name(consume, "consume");
  function read(size) {
    const toRead = Math.min(size, totalAvailable);
    if (toRead === 0) return null;
    const chunk = chunkQueue[0];
    if (chunk) {
      if (chunk.data.length - chunk.consumed >= toRead) {
        const result$1 = chunk.data.subarray(chunk.consumed, chunk.consumed + toRead);
        chunk.consumed += toRead;
        totalAvailable -= toRead;
        if (chunk.consumed >= chunk.data.length) chunkQueue.shift();
        return result$1;
      }
    }
    const result = new Uint8Array(toRead);
    let offset = 0;
    consume(toRead, (data) => {
      result.set(data, offset);
      offset += data.length;
    });
    return result;
  }
  __name(read, "read");
  function process2() {
    while (true) switch (state) {
      case STATE_HEADER: {
        if (totalAvailable < BLOCK_SIZE) {
          waitingForData = true;
          return;
        }
        const headerBlock = read(BLOCK_SIZE);
        if (!headerBlock) {
          waitingForData = true;
          return;
        }
        if (isZeroBlock(headerBlock)) {
          state = STATE_AWAIT_EOF;
          continue;
        }
        waitingForData = false;
        try {
          const internalHeader = parseUstarHeader(headerBlock, strict);
          const header = {
            ...internalHeader,
            name: internalHeader.name
          };
          const metaParser = getMetaParser(header.type);
          if (metaParser) {
            const paddedSize = header.size + BLOCK_SIZE_MASK & ~BLOCK_SIZE_MASK;
            if (totalAvailable < paddedSize) {
              waitingForData = true;
              chunkQueue.unshift({
                data: headerBlock,
                consumed: 0
              });
              totalAvailable += BLOCK_SIZE;
              return;
            }
            const metaBlock = read(paddedSize);
            if (!metaBlock) {
              waitingForData = true;
              return;
            }
            const overrides = metaParser(metaBlock.subarray(0, header.size));
            if (header.type === "pax-global-header") Object.assign(paxGlobals, overrides);
            else Object.assign(nextEntryOverrides, overrides);
            continue;
          }
          if (internalHeader.prefix) header.name = `${internalHeader.prefix}/${header.name}`;
          applyOverrides(header, paxGlobals);
          applyOverrides(header, nextEntryOverrides);
          nextEntryOverrides = {};
          handler.onHeader(header);
          if (header.size > 0) {
            currentEntry = {
              remaining: header.size,
              padding: -header.size & BLOCK_SIZE_MASK
            };
            state = STATE_BODY;
          } else handler.onEndEntry();
        } catch (error) {
          handler.onError(error);
          return;
        }
        continue;
      }
      case STATE_BODY: {
        if (!currentEntry) throw new Error("No current entry for body");
        const toForward = Math.min(currentEntry.remaining, totalAvailable);
        if (toForward > 0) {
          const consumed = consume(toForward, handler.onData);
          currentEntry.remaining -= consumed;
        }
        if (currentEntry.remaining === 0) {
          state = currentEntry.padding > 0 ? STATE_PADDING : STATE_HEADER;
          if (state === STATE_HEADER) {
            handler.onEndEntry();
            currentEntry = null;
          }
        } else if (totalAvailable === 0) {
          waitingForData = true;
          return;
        }
        continue;
      }
      case STATE_PADDING:
        if (!currentEntry) throw new Error("No current entry for padding");
        if (totalAvailable < currentEntry.padding) {
          waitingForData = true;
          return;
        }
        if (currentEntry.padding > 0) consume(currentEntry.padding);
        handler.onEndEntry();
        currentEntry = null;
        state = STATE_HEADER;
        continue;
      case STATE_AWAIT_EOF: {
        if (totalAvailable < BLOCK_SIZE) {
          waitingForData = true;
          return;
        }
        const secondBlock = read(BLOCK_SIZE);
        if (!secondBlock) {
          waitingForData = true;
          return;
        }
        if (isZeroBlock(secondBlock)) return;
        if (strict) {
          handler.onError(new Error("Invalid EOF"));
          return;
        }
        chunkQueue.unshift({
          data: secondBlock,
          consumed: 0
        });
        totalAvailable += BLOCK_SIZE;
        state = STATE_HEADER;
        continue;
      }
      default:
        throw new Error("Invalid state in tar unpacker.");
    }
  }
  __name(process2, "process");
  return {
    write(chunk) {
      if (chunk.length === 0) return;
      chunkQueue.push({
        data: chunk,
        consumed: 0
      });
      totalAvailable += chunk.length;
      if (waitingForData) {
        waitingForData = false;
        try {
          process2();
        } catch (error) {
          handler.onError(error);
        }
      }
    },
    end() {
      try {
        if (!waitingForData) process2();
        if (strict) {
          if (currentEntry && currentEntry.remaining > 0) {
            const error = new Error("Tar archive is truncated.");
            handler.onError(error);
            throw error;
          }
          if (totalAvailable > 0) {
            if (read(totalAvailable)?.some((b) => b !== 0)) {
              const error = new Error("Invalid EOF.");
              handler.onError(error);
              throw error;
            }
          }
          if (waitingForData) {
            const error = new Error("Tar archive is truncated.");
            handler.onError(error);
            throw error;
          }
        } else if (currentEntry) {
          handler.onEndEntry();
          currentEntry = null;
        }
      } catch (error) {
        handler.onError(error);
      }
    }
  };
}
__name(createTarUnpacker, "createTarUnpacker");
function isZeroBlock(block) {
  if (block.byteOffset % 8 === 0) {
    const view = new BigUint64Array(block.buffer, block.byteOffset, block.length / 8);
    for (let i = 0; i < view.length; i++) if (view[i] !== 0n) return false;
    return true;
  }
  for (let i = 0; i < block.length; i++) if (block[i] !== 0) return false;
  return true;
}
__name(isZeroBlock, "isZeroBlock");

// ../node_modules/modern-tar/dist/fs/index.js
import * as fs from "node:fs/promises";
import { cpus } from "node:os";
import * as path from "node:path";
import { PassThrough, Readable, Writable } from "node:stream";
import { createWriteStream } from "node:fs";
import { pipeline } from "node:stream/promises";
var unicodeCache = /* @__PURE__ */ new Map();
var normalizeUnicode = /* @__PURE__ */ __name((s) => {
  let result = unicodeCache.get(s);
  if (result !== void 0) unicodeCache.delete(s);
  result = result ?? s.normalize("NFD");
  unicodeCache.set(s, result);
  if (unicodeCache.size > 1e4) unicodeCache.delete(unicodeCache.keys().next().value);
  return result;
}, "normalizeUnicode");
function validateBounds(targetPath, destDir, errorMessage) {
  const target = normalizeUnicode(path.resolve(targetPath));
  const dest = path.resolve(destDir);
  if (target !== dest && !target.startsWith(dest + path.sep)) throw new Error(errorMessage);
}
__name(validateBounds, "validateBounds");
var win32Reserved = {
  ":": "\uF03A",
  "<": "\uF03C",
  ">": "\uF03E",
  "|": "\uF07C",
  "?": "\uF03F",
  "*": "\uF02A",
  '"': "\uF022"
};
function normalizeName(name) {
  const path$1 = name.replace(/\\/g, "/");
  if (path$1.split("/").includes("..") || /^[a-zA-Z]:\.\./.test(path$1)) throw new Error(`${name} points outside extraction directory`);
  let relative = path$1;
  if (/^[a-zA-Z]:/.test(relative)) relative = relative.replace(/^[a-zA-Z]:[/\\]?/, "");
  else if (relative.startsWith("/")) relative = relative.replace(/^\/+/, "");
  if (process.platform === "win32") return relative.replace(/[<>:"|?*]/g, (char) => win32Reserved[char]);
  return relative;
}
__name(normalizeName, "normalizeName");
var normalizeHeaderName = /* @__PURE__ */ __name((s) => normalizeUnicode(normalizeName(s.replace(/\/+$/, ""))), "normalizeHeaderName");
function unpackTar(directoryPath, options = {}) {
  const { streamTimeout = 5e3, ...fsOptions } = options;
  let timeoutId = null;
  const { handler, signal } = createFSHandler(directoryPath, fsOptions);
  const unpacker = createTarUnpacker(handler, fsOptions);
  let stream;
  function resetTimeout() {
    if (timeoutId) clearTimeout(timeoutId);
    if (streamTimeout !== Infinity && streamTimeout > 0) timeoutId = setTimeout(() => {
      const err = new Error(`Stream timed out after ${streamTimeout}ms of inactivity.`);
      stream.destroy(err);
    }, streamTimeout);
  }
  __name(resetTimeout, "resetTimeout");
  stream = new Writable({
    write(chunk, _, callback) {
      resetTimeout();
      if (signal.aborted) return callback(signal.reason);
      try {
        unpacker.write(chunk);
        callback();
      } catch (writeErr) {
        callback(writeErr);
      }
    },
    async final(callback) {
      if (timeoutId) clearTimeout(timeoutId);
      try {
        if (signal.aborted) return callback(signal.reason);
        unpacker.end();
        await handler.process();
        callback();
      } catch (finalErr) {
        callback(finalErr);
      }
    }
  });
  stream.on("close", () => {
    if (timeoutId) clearTimeout(timeoutId);
  });
  resetTimeout();
  return stream;
}
__name(unpackTar, "unpackTar");
function createFSHandler(directoryPath, options) {
  const { maxDepth = 1024, dmode, fmode, concurrency = cpus().length || 8 } = options;
  const abortController = new AbortController();
  const { signal } = abortController;
  const opQueue = [];
  let activeOps = 0;
  const pathPromises = /* @__PURE__ */ new Map();
  let activeEntryStream = null;
  let processingEnded = false;
  let resolveDrain;
  const drainPromise = new Promise((resolve4) => {
    resolveDrain = resolve4;
  });
  const processQueue = /* @__PURE__ */ __name(() => {
    if (signal.aborted) opQueue.length = 0;
    while (activeOps < concurrency && opQueue.length > 0) {
      activeOps++;
      const op = opQueue.shift();
      if (!op) break;
      op();
    }
    if (processingEnded && activeOps === 0 && opQueue.length === 0) resolveDrain();
  }, "processQueue");
  const destDirPromise = (async () => {
    const symbolic = normalizeUnicode(path.resolve(directoryPath));
    await fs.mkdir(symbolic, { recursive: true });
    try {
      const real = await fs.realpath(symbolic);
      return {
        symbolic,
        real
      };
    } catch (err) {
      if (signal.aborted) throw signal.reason;
      throw err;
    }
  })();
  destDirPromise.catch((err) => {
    if (!signal.aborted) abortController.abort(err);
  });
  const ensureDirectoryExists = /* @__PURE__ */ __name((dirPath) => {
    let promise = pathPromises.get(dirPath);
    if (promise) return promise;
    promise = (async () => {
      if (signal.aborted) throw signal.reason;
      const destDir = await destDirPromise;
      if (dirPath === destDir.symbolic) return "directory";
      await ensureDirectoryExists(path.dirname(dirPath));
      if (signal.aborted) throw signal.reason;
      try {
        const stat2 = await fs.lstat(dirPath);
        if (stat2.isDirectory()) return "directory";
        if (stat2.isSymbolicLink()) {
          const realPath = await fs.realpath(dirPath);
          validateBounds(realPath, destDir.real, `Symlink "${dirPath}" points outside the extraction directory.`);
          if ((await fs.stat(realPath)).isDirectory()) return "directory";
        }
        throw new Error(`"${dirPath}" is not a valid directory component.`);
      } catch (err) {
        if (err.code === "ENOENT") {
          await fs.mkdir(dirPath, { mode: dmode });
          return "directory";
        }
        throw err;
      }
    })();
    pathPromises.set(dirPath, promise);
    return promise;
  }, "ensureDirectoryExists");
  return {
    handler: {
      onHeader(header) {
        if (signal.aborted) return;
        activeEntryStream = new PassThrough({ highWaterMark: header.size > 1048576 ? 524288 : void 0 });
        const entryStream = activeEntryStream;
        const startOperation = /* @__PURE__ */ __name(() => {
          let opPromise;
          try {
            const transformed = transformHeader(header, options);
            if (!transformed) {
              entryStream.resume();
              activeOps--;
              processQueue();
              return;
            }
            const name = normalizeHeaderName(transformed.name);
            const target = path.join(path.resolve(directoryPath), name);
            opPromise = (pathPromises.get(target) || Promise.resolve(void 0)).then(async (priorOp) => {
              if (signal.aborted) throw signal.reason;
              if (priorOp) {
                if (priorOp === "directory" && transformed.type !== "directory" || priorOp !== "directory" && transformed.type === "directory") throw new Error(`Path conflict ${transformed.type} over existing ${priorOp} at "${transformed.name}"`);
              }
              try {
                const destDir = await destDirPromise;
                if (maxDepth !== Infinity && name.split("/").length > maxDepth) throw new Error("Tar exceeds max specified depth.");
                const outPath = path.join(destDir.symbolic, name);
                validateBounds(outPath, destDir.symbolic, `Entry "${transformed.name}" points outside the extraction directory.`);
                const parentDir = path.dirname(outPath);
                await ensureDirectoryExists(parentDir);
                switch (transformed.type) {
                  case "directory":
                    await fs.mkdir(outPath, {
                      recursive: true,
                      mode: dmode ?? transformed.mode
                    });
                    break;
                  case "file": {
                    const fileStream = createWriteStream(outPath, {
                      mode: fmode ?? transformed.mode,
                      highWaterMark: transformed.size > 1048576 ? 524288 : void 0
                    });
                    await pipeline(entryStream, fileStream);
                    break;
                  }
                  case "symlink": {
                    const { linkname } = transformed;
                    if (!linkname) return transformed.type;
                    const target$1 = path.resolve(parentDir, linkname);
                    validateBounds(target$1, destDir.symbolic, `Symlink "${linkname}" points outside the extraction directory.`);
                    await fs.symlink(linkname, outPath);
                    break;
                  }
                  case "link": {
                    const { linkname } = transformed;
                    if (!linkname) return transformed.type;
                    const normalizedLink = normalizeUnicode(linkname);
                    if (path.isAbsolute(normalizedLink)) throw new Error(`Hardlink "${linkname}" points outside the extraction directory.`);
                    const linkTarget = path.join(destDir.symbolic, normalizedLink);
                    validateBounds(linkTarget, destDir.symbolic, `Hardlink "${linkname}" points outside the extraction directory.`);
                    await ensureDirectoryExists(path.dirname(linkTarget));
                    const realTargetParent = await fs.realpath(path.dirname(linkTarget));
                    const realLinkTarget = path.join(realTargetParent, path.basename(linkTarget));
                    validateBounds(realLinkTarget, destDir.real, `Hardlink "${linkname}" points outside the extraction directory.`);
                    if (linkTarget === outPath) return transformed.type;
                    const targetPromise = pathPromises.get(linkTarget);
                    if (targetPromise) await targetPromise;
                    await fs.link(linkTarget, outPath);
                    break;
                  }
                  default:
                    return transformed.type;
                }
                if (transformed.mtime) await (transformed.type === "symlink" ? fs.lutimes : fs.utimes)(outPath, transformed.mtime, transformed.mtime).catch(() => {
                });
                return transformed.type;
              } finally {
                if (!entryStream.readableEnded) entryStream.resume();
              }
            });
            pathPromises.set(target, opPromise);
          } catch (err) {
            opPromise = Promise.reject(err);
            abortController.abort(err);
          }
          opPromise.catch((err) => abortController.abort(err)).finally(() => {
            activeOps--;
            processQueue();
          });
        }, "startOperation");
        opQueue.push(startOperation);
        processQueue();
      },
      onData(chunk) {
        if (!signal.aborted) activeEntryStream?.write(chunk);
      },
      onEndEntry() {
        activeEntryStream?.end();
        activeEntryStream = null;
      },
      onError(error) {
        abortController.abort(error);
      },
      async process() {
        processingEnded = true;
        processQueue();
        await drainPromise;
        if (signal.aborted) throw signal.reason;
      }
    },
    signal
  };
}
__name(createFSHandler, "createFSHandler");

// src/cli/dirs.ts
var resolveUsingBranchInstall = /* @__PURE__ */ __name(async (packageManager, request) => {
  const tempDirectory = await temporaryDirectory();
  const name = request;
  const version = versions[name] || await packageManager.latestVersion(request);
  const getNpmTarballUrl = src_default.default || src_default;
  const url = getNpmTarballUrl(request, version, {
    registry: await packageManager.getRegistryURL()
  });
  const response = await fetch(url);
  if (!response.ok || !response.body) {
    throw new Error(`Failed to download tarball from ${url}`);
  }
  await pipeline2(
    Readable2.fromWeb(response.body),
    createGunzip(),
    unpackTar(tempDirectory)
  );
  return join2(tempDirectory, "package");
}, "resolveUsingBranchInstall");
async function getRendererDir(packageManager, renderer) {
  const externalFramework = externalFrameworks.find((framework) => framework.name === renderer);
  const frameworkPackageName = externalFramework?.packageName || externalFramework?.renderer || `@storybook/${renderer}`;
  const packageJsonPath = join2(frameworkPackageName, "package.json");
  const errors = [];
  try {
    return resolvePackageDir(frameworkPackageName, process.cwd());
  } catch (e) {
    invariant(e instanceof Error);
    errors.push(e);
  }
  try {
    return await resolveUsingBranchInstall(packageManager, frameworkPackageName);
  } catch (e) {
    invariant(e instanceof Error);
    errors.push(e);
  }
  throw new Error(`Cannot find ${packageJsonPath}, ${errors.map((e) => e.stack).join("\n\n")}`);
}
__name(getRendererDir, "getRendererDir");

// src/cli/helpers.ts
import { cpSync, existsSync, readFileSync, writeFileSync } from "node:fs";
import { cp, readFile as readFile2, writeFile } from "node:fs/promises";
import { join as join3, resolve as resolve2 } from "node:path";
import {
  frameworkToRenderer,
  getProjectRoot
} from "storybook/internal/common";
import { logger } from "storybook/internal/node-logger";
var import_picocolors = __toESM(require_picocolors(), 1);
import { coerce, satisfies } from "semver";

// ../node_modules/strip-json-comments/index.js
var singleComment = Symbol("singleComment");
var multiComment = Symbol("multiComment");
var stripWithoutWhitespace = /* @__PURE__ */ __name(() => "", "stripWithoutWhitespace");
var stripWithWhitespace = /* @__PURE__ */ __name((string, start, end) => string.slice(start, end).replace(/[^ \t\r\n]/g, " "), "stripWithWhitespace");
var isEscaped = /* @__PURE__ */ __name((jsonString, quotePosition) => {
  let index = quotePosition - 1;
  let backslashCount = 0;
  while (jsonString[index] === "\\") {
    index -= 1;
    backslashCount += 1;
  }
  return Boolean(backslashCount % 2);
}, "isEscaped");
function stripJsonComments(jsonString, { whitespace = true, trailingCommas = false } = {}) {
  if (typeof jsonString !== "string") {
    throw new TypeError(`Expected argument \`jsonString\` to be a \`string\`, got \`${typeof jsonString}\``);
  }
  const strip = whitespace ? stripWithWhitespace : stripWithoutWhitespace;
  let isInsideString = false;
  let isInsideComment = false;
  let offset = 0;
  let buffer = "";
  let result = "";
  let commaIndex = -1;
  for (let index = 0; index < jsonString.length; index++) {
    const currentCharacter = jsonString[index];
    const nextCharacter = jsonString[index + 1];
    if (!isInsideComment && currentCharacter === '"') {
      const escaped = isEscaped(jsonString, index);
      if (!escaped) {
        isInsideString = !isInsideString;
      }
    }
    if (isInsideString) {
      continue;
    }
    if (!isInsideComment && currentCharacter + nextCharacter === "//") {
      buffer += jsonString.slice(offset, index);
      offset = index;
      isInsideComment = singleComment;
      index++;
    } else if (isInsideComment === singleComment && currentCharacter + nextCharacter === "\r\n") {
      index++;
      isInsideComment = false;
      buffer += strip(jsonString, offset, index);
      offset = index;
      continue;
    } else if (isInsideComment === singleComment && currentCharacter === "\n") {
      isInsideComment = false;
      buffer += strip(jsonString, offset, index);
      offset = index;
    } else if (!isInsideComment && currentCharacter + nextCharacter === "/*") {
      buffer += jsonString.slice(offset, index);
      offset = index;
      isInsideComment = multiComment;
      index++;
      continue;
    } else if (isInsideComment === multiComment && currentCharacter + nextCharacter === "*/") {
      index++;
      isInsideComment = false;
      buffer += strip(jsonString, offset, index + 1);
      offset = index + 1;
      continue;
    } else if (trailingCommas && !isInsideComment) {
      if (commaIndex !== -1) {
        if (currentCharacter === "}" || currentCharacter === "]") {
          buffer += jsonString.slice(offset, index);
          result += strip(buffer, 0, 1) + buffer.slice(1);
          buffer = "";
          offset = index;
          commaIndex = -1;
        } else if (currentCharacter !== " " && currentCharacter !== "	" && currentCharacter !== "\r" && currentCharacter !== "\n") {
          buffer += jsonString.slice(offset, index);
          offset = index;
          commaIndex = -1;
        }
      } else if (currentCharacter === ",") {
        result += buffer + jsonString.slice(offset, index);
        buffer = "";
        offset = index;
        commaIndex = index;
      }
    }
  }
  const remaining = isInsideComment === singleComment ? strip(jsonString, offset) : jsonString.slice(offset);
  return result + buffer + remaining;
}
__name(stripJsonComments, "stripJsonComments");

// src/cli/helpers.ts
function readFileAsJson(jsonPath, allowComments) {
  const filePath = resolve2(jsonPath);
  if (!existsSync(filePath)) {
    return false;
  }
  const fileContent = readFileSync(filePath, "utf8");
  const jsonContent = allowComments ? stripJsonComments(fileContent) : fileContent;
  try {
    return JSON.parse(jsonContent);
  } catch (e) {
    logger.error(import_picocolors.default.red(`Invalid json in file: ${filePath}`));
    throw e;
  }
}
__name(readFileAsJson, "readFileAsJson");
var writeFileAsJson = /* @__PURE__ */ __name((jsonPath, content) => {
  const filePath = resolve2(jsonPath);
  if (!existsSync(filePath)) {
    return false;
  }
  writeFileSync(filePath, `${JSON.stringify(content, null, 2)}
`);
  return true;
}, "writeFileAsJson");
async function getBabelDependencies(packageManager) {
  const dependenciesToAdd = [];
  let babelLoaderVersion = "^8.0.0-0";
  const babelCoreVersion = packageManager.getDependencyVersion("babel-core");
  if (!babelCoreVersion) {
    if (!packageManager.getDependencyVersion("@babel/core")) {
      const babelCoreInstallVersion = await packageManager.getVersion("@babel/core");
      dependenciesToAdd.push(`@babel/core@${babelCoreInstallVersion}`);
    }
  } else {
    const latestCompatibleBabelVersion = await packageManager.latestVersion(
      "babel-core",
      babelCoreVersion
    );
    if (latestCompatibleBabelVersion && satisfies(latestCompatibleBabelVersion, "^6.0.0")) {
      babelLoaderVersion = "^7.0.0";
    }
  }
  if (!packageManager.getDependencyVersion("babel-loader")) {
    const babelLoaderInstallVersion = await packageManager.getVersion(
      "babel-loader",
      babelLoaderVersion
    );
    dependenciesToAdd.push(`babel-loader@${babelLoaderInstallVersion}`);
  }
  return dependenciesToAdd;
}
__name(getBabelDependencies, "getBabelDependencies");
function addToDevDependenciesIfNotPresent(packageJson, name, packageVersion) {
  if (!packageJson.dependencies?.[name] && !packageJson.devDependencies?.[name]) {
    if (packageJson.devDependencies) {
      packageJson.devDependencies[name] = packageVersion;
    } else {
      packageJson.devDependencies = {
        [name]: packageVersion
      };
    }
  }
}
__name(addToDevDependenciesIfNotPresent, "addToDevDependenciesIfNotPresent");
function copyTemplate(templateRoot, destination = ".") {
  const templateDir = resolve2(templateRoot, `template-csf/`);
  if (!existsSync(templateDir)) {
    throw new Error(`Couldn't find template dir`);
  }
  cpSync(templateDir, destination, { recursive: true });
}
__name(copyTemplate, "copyTemplate");
var frameworkToDefaultBuilder = {
  angular: "webpack5" /* Webpack5 */,
  ember: "webpack5" /* Webpack5 */,
  "html-vite": "vite" /* Vite */,
  nextjs: "webpack5" /* Webpack5 */,
  nuxt: "vite" /* Vite */,
  "nextjs-vite": "vite" /* Vite */,
  "preact-vite": "vite" /* Vite */,
  qwik: "vite" /* Vite */,
  "react-native-web-vite": "vite" /* Vite */,
  "react-vite": "vite" /* Vite */,
  "react-webpack5": "webpack5" /* Webpack5 */,
  "server-webpack5": "webpack5" /* Webpack5 */,
  solid: "vite" /* Vite */,
  "svelte-vite": "vite" /* Vite */,
  sveltekit: "vite" /* Vite */,
  "vue3-vite": "vite" /* Vite */,
  "web-components-vite": "vite" /* Vite */,
  // Only to pass type checking, will never be used
  "react-rsbuild": "rsbuild" /* Rsbuild */,
  "vue3-rsbuild": "rsbuild" /* Rsbuild */
};
async function getVersionSafe(packageManager, packageName) {
  try {
    let version = await packageManager.getInstalledVersion(packageName);
    if (!version) {
      const deps = packageManager.getAllDependencies();
      const versionSpecifier = deps[packageName];
      version = versionSpecifier ?? "";
    }
    const coerced = coerce(version, { includePrerelease: true });
    return coerced?.toString();
  } catch (err) {
  }
  return void 0;
}
__name(getVersionSafe, "getVersionSafe");
var cliStoriesTargetPath = /* @__PURE__ */ __name(async () => {
  if (existsSync("./src")) {
    return "./src/stories";
  }
  return "./stories";
}, "cliStoriesTargetPath");
async function copyTemplateFiles({
  packageManager,
  templateLocation,
  language,
  destination,
  commonAssetsDir,
  features
}) {
  const languageFolderMapping = {
    ["javascript" /* JAVASCRIPT */]: "js",
    ["typescript" /* TYPESCRIPT */]: "ts"
  };
  const templatePath = /* @__PURE__ */ __name(async () => {
    const baseDir = await getRendererDir(packageManager, templateLocation);
    const assetsDir = join3(baseDir, "template", "cli");
    const assetsLanguage = join3(assetsDir, languageFolderMapping[language]);
    const assetsJS = join3(assetsDir, languageFolderMapping["javascript" /* JAVASCRIPT */]);
    const assetsTS = join3(assetsDir, languageFolderMapping.typescript);
    if (existsSync(assetsLanguage)) {
      return assetsLanguage;
    }
    if (existsSync(assetsTS)) {
      return assetsTS;
    }
    if (existsSync(assetsJS)) {
      return assetsJS;
    }
    if (existsSync(assetsDir)) {
      return assetsDir;
    }
    throw new Error(`Unsupported renderer: ${templateLocation} (${baseDir})`);
  }, "templatePath");
  const destinationPath = destination ?? await cliStoriesTargetPath();
  const filter = /* @__PURE__ */ __name((file) => features.includes("docs") || !file.endsWith(".mdx"), "filter");
  if (commonAssetsDir) {
    await cp(commonAssetsDir, destinationPath, { recursive: true, filter });
  }
  await cp(await templatePath(), destinationPath, { recursive: true, filter });
  if (commonAssetsDir && features.includes("docs")) {
    let rendererType = frameworkToRenderer[templateLocation] || "react";
    if (rendererType === "vue3") {
      rendererType = "vue";
    }
    await adjustTemplate(join3(destinationPath, "Configure.mdx"), { renderer: rendererType });
  }
}
__name(copyTemplateFiles, "copyTemplateFiles");
async function adjustTemplate(templatePath, templateData) {
  let template = await readFile2(templatePath, { encoding: "utf8" });
  Object.keys(templateData).forEach((key) => {
    template = template.replaceAll(`{{${key}}}`, `${templateData[key]}`);
  });
  await writeFile(templatePath, template);
}
__name(adjustTemplate, "adjustTemplate");
async function isNxProject() {
  return up("nx.json", { last: getProjectRoot() });
}
__name(isNxProject, "isNxProject");
function coerceSemver(version) {
  const coercedSemver = coerce(version);
  invariant(coercedSemver != null, `Could not coerce ${version} into a semver.`);
  return coercedSemver;
}
__name(coerceSemver, "coerceSemver");
function hasStorybookDependencies(packageManager) {
  const currentPackageDeps = packageManager.getAllDependencies();
  return Object.keys(currentPackageDeps).some((dep) => dep.includes("storybook"));
}
__name(hasStorybookDependencies, "hasStorybookDependencies");

// src/cli/detect.ts
import { existsSync as existsSync2 } from "node:fs";
import { resolve as resolve3 } from "node:path";
import { HandledError, commandLog, getProjectRoot as getProjectRoot2 } from "storybook/internal/common";
import { logger as logger2 } from "storybook/internal/node-logger";
var import_prompts = __toESM(require_prompts(), 1);
import semver from "semver";
var viteConfigFiles = ["vite.config.ts", "vite.config.js", "vite.config.mjs"];
var webpackConfigFiles = ["webpack.config.js"];
var hasDependency = /* @__PURE__ */ __name((packageJson, name, matcher) => {
  const version = packageJson.dependencies?.[name] || packageJson.devDependencies?.[name];
  if (version && typeof matcher === "function") {
    return matcher(version);
  }
  return !!version;
}, "hasDependency");
var hasPeerDependency = /* @__PURE__ */ __name((packageJson, name, matcher) => {
  const version = packageJson.peerDependencies?.[name];
  if (version && typeof matcher === "function") {
    return matcher(version);
  }
  return !!version;
}, "hasPeerDependency");
var getFrameworkPreset = /* @__PURE__ */ __name((packageJson, framework) => {
  const matcher = {
    dependencies: [false],
    peerDependencies: [false],
    files: [false]
  };
  const { preset, files, dependencies, peerDependencies, matcherFunction } = framework;
  let dependencySearches = [];
  if (Array.isArray(dependencies)) {
    dependencySearches = dependencies.map((name) => [name, void 0]);
  } else if (typeof dependencies === "object") {
    dependencySearches = Object.entries(dependencies);
  }
  if (dependencySearches.length > 0) {
    matcher.dependencies = dependencySearches.map(
      ([name, matchFn]) => hasDependency(packageJson, name, matchFn)
    );
  }
  let peerDependencySearches = [];
  if (Array.isArray(peerDependencies)) {
    peerDependencySearches = peerDependencies.map((name) => [name, void 0]);
  } else if (typeof peerDependencies === "object") {
    peerDependencySearches = Object.entries(peerDependencies);
  }
  if (peerDependencySearches.length > 0) {
    matcher.peerDependencies = peerDependencySearches.map(
      ([name, matchFn]) => hasPeerDependency(packageJson, name, matchFn)
    );
  }
  if (Array.isArray(files) && files.length > 0) {
    matcher.files = files.map((name) => existsSync2(name));
  }
  return matcherFunction(matcher) ? preset : null;
}, "getFrameworkPreset");
function detectFrameworkPreset(packageJson = {}) {
  const result = [...supportedTemplates, unsupportedTemplate].find((framework) => {
    return getFrameworkPreset(packageJson, framework) !== null;
  });
  return result ? result.preset : "UNDETECTED" /* UNDETECTED */;
}
__name(detectFrameworkPreset, "detectFrameworkPreset");
async function detectBuilder(packageManager, projectType) {
  const viteConfig = any(viteConfigFiles, { last: getProjectRoot2() });
  const webpackConfig = any(webpackConfigFiles, { last: getProjectRoot2() });
  const dependencies = packageManager.getAllDependencies();
  if (viteConfig || dependencies.vite && dependencies.webpack === void 0) {
    commandLog("Detected Vite project. Setting builder to Vite")();
    return "vite" /* Vite */;
  }
  if (webpackConfig || (dependencies.webpack || dependencies["@nuxt/webpack-builder"]) && dependencies.vite !== void 0) {
    commandLog("Detected webpack project. Setting builder to webpack")();
    return "webpack5" /* Webpack5 */;
  }
  switch (projectType) {
    case "REACT_NATIVE_AND_RNW" /* REACT_NATIVE_AND_RNW */:
    case "REACT_NATIVE_WEB" /* REACT_NATIVE_WEB */:
      return "vite" /* Vite */;
    case "REACT_SCRIPTS" /* REACT_SCRIPTS */:
    case "ANGULAR" /* ANGULAR */:
    case "REACT_NATIVE" /* REACT_NATIVE */:
    // technically react native doesn't use webpack, we just want to set something
    case "NEXTJS" /* NEXTJS */:
    case "EMBER" /* EMBER */:
      return "webpack5" /* Webpack5 */;
    case "NUXT" /* NUXT */:
      return "vite" /* Vite */;
    default:
      const { builder } = await (0, import_prompts.default)(
        {
          type: "select",
          name: "builder",
          message: "\nWe were not able to detect the right builder for your project. Please select one:",
          choices: [
            { title: "Vite", value: "vite" /* Vite */ },
            { title: "Webpack 5", value: "webpack5" /* Webpack5 */ }
          ]
        },
        {
          onCancel: /* @__PURE__ */ __name(() => {
            throw new HandledError("Canceled by the user");
          }, "onCancel")
        }
      );
      return builder;
  }
}
__name(detectBuilder, "detectBuilder");
function isStorybookInstantiated(configDir = resolve3(process.cwd(), ".storybook")) {
  return existsSync2(configDir);
}
__name(isStorybookInstantiated, "isStorybookInstantiated");
async function detectPnp() {
  return !!any([".pnp.js", ".pnp.cjs"]);
}
__name(detectPnp, "detectPnp");
async function detectLanguage(packageManager) {
  let language = "javascript" /* JAVASCRIPT */;
  if (existsSync2("jsconfig.json")) {
    return language;
  }
  const isTypescriptDirectDependency = !!packageManager.getAllDependencies().typescript;
  const getModulePackageJSONVersion = /* @__PURE__ */ __name(async (pkg) => {
    return (await packageManager.getModulePackageJSON(pkg))?.version ?? null;
  }, "getModulePackageJSONVersion");
  const [
    typescriptVersion,
    prettierVersion,
    babelPluginTransformTypescriptVersion,
    typescriptEslintParserVersion,
    eslintPluginStorybookVersion
  ] = await Promise.all([
    getModulePackageJSONVersion("typescript"),
    getModulePackageJSONVersion("prettier"),
    getModulePackageJSONVersion("@babel/plugin-transform-typescript"),
    getModulePackageJSONVersion("@typescript-eslint/parser"),
    getModulePackageJSONVersion("eslint-plugin-storybook")
  ]);
  if (isTypescriptDirectDependency && typescriptVersion) {
    if (semver.gte(typescriptVersion, "4.9.0") && (!prettierVersion || semver.gte(prettierVersion, "2.8.0")) && (!babelPluginTransformTypescriptVersion || semver.gte(babelPluginTransformTypescriptVersion, "7.20.0")) && (!typescriptEslintParserVersion || semver.gte(typescriptEslintParserVersion, "5.44.0")) && (!eslintPluginStorybookVersion || semver.gte(eslintPluginStorybookVersion, "0.6.8"))) {
      language = "typescript" /* TYPESCRIPT */;
    } else {
      logger2.warn(
        "Detected TypeScript < 4.9 or incompatible tooling, populating with JavaScript examples"
      );
    }
  } else {
    if (existsSync2("tsconfig.json")) {
      language = "typescript" /* TYPESCRIPT */;
    }
  }
  return language;
}
__name(detectLanguage, "detectLanguage");
async function detect(packageManager, options = {}) {
  try {
    if (await isNxProject()) {
      return "NX" /* NX */;
    }
    if (options.html) {
      return "HTML" /* HTML */;
    }
    const { packageJson } = packageManager.primaryPackageJson;
    return detectFrameworkPreset(packageJson);
  } catch (e) {
    return "UNDETECTED" /* UNDETECTED */;
  }
}
__name(detect, "detect");

export {
  externalFrameworks,
  SUPPORTED_RENDERERS,
  ProjectType,
  CoreBuilder,
  CoreWebpackCompilers,
  CommunityBuilder,
  compilerNameToCoreCompiler,
  builderNameToCoreBuilder,
  SupportedLanguage,
  supportedTemplates,
  unsupportedTemplate,
  installableProjectTypes,
  getRendererDir,
  readFileAsJson,
  writeFileAsJson,
  getBabelDependencies,
  addToDevDependenciesIfNotPresent,
  copyTemplate,
  frameworkToDefaultBuilder,
  getVersionSafe,
  cliStoriesTargetPath,
  copyTemplateFiles,
  adjustTemplate,
  isNxProject,
  coerceSemver,
  hasStorybookDependencies,
  detectFrameworkPreset,
  detectBuilder,
  isStorybookInstantiated,
  detectPnp,
  detectLanguage,
  detect
};
