var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
  for (var prop in b || (b = {}))
    if (__hasOwnProp.call(b, prop))
      __defNormalProp(a, prop, b[prop]);
  if (__getOwnPropSymbols)
    for (var prop of __getOwnPropSymbols(b)) {
      if (__propIsEnum.call(b, prop))
        __defNormalProp(a, prop, b[prop]);
    }
  return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));

// src/constants.ts
var MODULE_IDS = [
  "~pages",
  "~react-pages",
  "~solid-pages",
  "pages-generated",
  "virtual:generated-pages",
  "virtual:generated-pages-react"
];
var MODULE_ID_VIRTUAL = "virtual:vite-plugin-pages/generated-pages";
var ROUTE_BLOCK_ID_VIRTUAL = "virtual:vite-plugin-pages/route-block";
var ROUTE_IMPORT_NAME = "__pages_import_$1__";
var routeBlockQueryRE = /\?vue&type=route/;
var dynamicRouteRE = /^\[(.+)\]$/;
var cacheAllRouteRE = /^\[\.{3}(.*)\]$/;
var replaceDynamicRouteRE = /^\[(?:\.{3})?(.*)\]$/;
var nuxtDynamicRouteRE = /^_(.*)$/;
var nuxtCacheAllRouteRE = /^_$/;
var countSlashRE = /\//g;
var replaceIndexRE = /\/?index$/;

// src/context.ts
import { join as join2, resolve as resolve3 } from "node:path";
import process2 from "node:process";

// node_modules/.pnpm/@antfu+utils@9.1.0/node_modules/@antfu/utils/dist/index.mjs
function toArray(array) {
  array = array != null ? array : [];
  return Array.isArray(array) ? array : [array];
}
function slash(str) {
  return str.replace(/\\/g, "/");
}
var VOID = Symbol("p-void");

// src/files.ts
import { join } from "node:path";
import { globSync } from "tinyglobby";

// src/utils.ts
import { resolve, win32 } from "node:path";
import { URLSearchParams } from "node:url";
import Debug from "debug";
import micromatch from "micromatch";
var debug = {
  hmr: Debug("vite-plugin-pages:hmr"),
  routeBlock: Debug("vite-plugin-pages:routeBlock"),
  options: Debug("vite-plugin-pages:options"),
  pages: Debug("vite-plugin-pages:pages"),
  search: Debug("vite-plugin-pages:search"),
  env: Debug("vite-plugin-pages:env"),
  cache: Debug("vite-plugin-pages:cache"),
  resolver: Debug("vite-plugin-pages:resolver")
};
function extsToGlob(extensions) {
  return extensions.length > 1 ? `{${extensions.join(",")}}` : extensions[0] || "";
}
function countSlash(value) {
  return (value.match(countSlashRE) || []).length;
}
function isPagesDir(path, options) {
  for (const page of options.dirs) {
    const dirPath = slash(resolve(options.root, page.dir));
    if (path.startsWith(dirPath))
      return true;
  }
  return false;
}
function isTarget(path, options) {
  return isPagesDir(path, options) && !micromatch.isMatch(path, options.exclude) && options.extensionsRE.test(path);
}
function isDynamicRoute(routePath, nuxtStyle = false) {
  return nuxtStyle ? nuxtDynamicRouteRE.test(routePath) : dynamicRouteRE.test(routePath);
}
function isCatchAllRoute(routePath, nuxtStyle = false) {
  return nuxtStyle ? nuxtCacheAllRouteRE.test(routePath) : cacheAllRouteRE.test(routePath);
}
function resolveImportMode(filepath, options) {
  const mode = options.importMode;
  if (typeof mode === "function")
    return mode(filepath, options);
  return mode;
}
function invalidatePagesModule(server) {
  const { moduleGraph } = server;
  const mods = moduleGraph.getModulesByFile(MODULE_ID_VIRTUAL);
  if (mods) {
    const seen = /* @__PURE__ */ new Set();
    mods.forEach((mod) => {
      moduleGraph.invalidateModule(mod, seen);
    });
  }
}
function normalizeCase(str, caseSensitive) {
  if (!caseSensitive)
    return str.toLocaleLowerCase();
  return str;
}
function normalizeName(name, isDynamic, nuxtStyle = false) {
  if (!isDynamic)
    return name;
  return nuxtStyle ? name.replace(nuxtDynamicRouteRE, "$1") || "all" : name.replace(replaceDynamicRouteRE, "$1");
}
function buildReactRoutePath(node, nuxtStyle = false) {
  const isDynamic = isDynamicRoute(node, nuxtStyle);
  const isCatchAll = isCatchAllRoute(node, nuxtStyle);
  const normalizedName = normalizeName(node, isDynamic, nuxtStyle);
  if (isDynamic) {
    if (isCatchAll)
      return "*";
    return `:${normalizedName}`;
  }
  return `${normalizedName}`;
}
function buildReactRemixRoutePath(node) {
  const escapeStart = "[";
  const escapeEnd = "]";
  let result = "";
  let rawSegmentBuffer = "";
  let inEscapeSequence = 0;
  let skipSegment = false;
  for (let i = 0; i < node.length; i++) {
    let isNewEscapeSequence2 = function() {
      return !inEscapeSequence && char === escapeStart && lastChar !== escapeStart;
    }, isCloseEscapeSequence2 = function() {
      return inEscapeSequence && char === escapeEnd && nextChar !== escapeEnd;
    }, isStartOfLayoutSegment2 = function() {
      return char === "_" && nextChar === "_" && !rawSegmentBuffer;
    };
    var isNewEscapeSequence = isNewEscapeSequence2, isCloseEscapeSequence = isCloseEscapeSequence2, isStartOfLayoutSegment = isStartOfLayoutSegment2;
    const char = node.charAt(i);
    const lastChar = i > 0 ? node.charAt(i - 1) : void 0;
    const nextChar = i < node.length - 1 ? node.charAt(i + 1) : void 0;
    if (skipSegment) {
      if (char === "/" || char === "." || char === win32.sep)
        skipSegment = false;
      continue;
    }
    if (isNewEscapeSequence2()) {
      inEscapeSequence++;
      continue;
    }
    if (isCloseEscapeSequence2()) {
      inEscapeSequence--;
      continue;
    }
    if (inEscapeSequence) {
      result += char;
      continue;
    }
    if (char === "/" || char === win32.sep || char === ".") {
      if (rawSegmentBuffer === "index" && result.endsWith("index"))
        result = result.replace(replaceIndexRE, "");
      else result += "/";
      rawSegmentBuffer = "";
      continue;
    }
    if (isStartOfLayoutSegment2()) {
      skipSegment = true;
      continue;
    }
    rawSegmentBuffer += char;
    if (char === "$") {
      result += typeof nextChar === "undefined" ? "*" : ":";
      continue;
    }
    result += char;
  }
  if (rawSegmentBuffer === "index" && result.endsWith("index"))
    result = result.replace(replaceIndexRE, "");
  return result || void 0;
}
function parsePageRequest(id) {
  const [moduleId, rawQuery] = id.split("?", 2);
  const query = new URLSearchParams(rawQuery);
  const pageId = query.get("id");
  return {
    moduleId,
    query,
    pageId
  };
}

// src/files.ts
function getPageDirs(PageOptions, root, exclude) {
  const dirs = globSync(slash(PageOptions.dir), {
    ignore: exclude,
    onlyDirectories: true,
    dot: true,
    expandDirectories: false,
    cwd: root
  });
  const pageDirs = dirs.map((dir) => __spreadProps(__spreadValues({}, PageOptions), {
    dir: dir.replace(/\/$/, "")
  }));
  return pageDirs;
}
function getPageFiles(path, options, pageOptions) {
  var _a;
  const {
    exclude,
    extensions
  } = options;
  const ext = extsToGlob(extensions);
  const pattern = (_a = pageOptions == null ? void 0 : pageOptions.filePattern) != null ? _a : `**/*.${ext}`;
  const files = globSync(pattern, {
    ignore: exclude,
    onlyFiles: true,
    cwd: path
  }).map((p) => slash(join(path, p)));
  return files;
}

// src/options.ts
import { resolve as resolve2 } from "node:path";
import process from "node:process";

// src/stringify.ts
var componentRE = /"(?:component|element)":("(.*?)")/g;
var hasFunctionRE = /"(?:props|beforeEnter)":("(.*?)")/g;
var multilineCommentsRE = /\/\*(.|[\r\n])*?\*\//g;
var singlelineCommentsRE = /\/\/.*/g;
function replaceFunction(_, value) {
  if (typeof value === "function" || typeof value === "function") {
    const fnBody = value.toString().replace(multilineCommentsRE, "").replace(singlelineCommentsRE, "").replace(/(\s)/g, "");
    if (fnBody.length < 8 || fnBody.substring(0, 8) !== "function")
      return `_NuFrRa_${fnBody}`;
    return fnBody;
  }
  return value;
}
function stringifyRoutes(preparedRoutes, options) {
  const importsMap = /* @__PURE__ */ new Map();
  function getImportString(path, importName) {
    var _a, _b;
    const mode = resolveImportMode(path, options);
    return mode === "sync" ? `import ${importName} from "${path}"` : `const ${importName} = ${((_b = (_a = options.resolver.stringify) == null ? void 0 : _a.dynamicImport) == null ? void 0 : _b.call(_a, path)) || `() => import("${path}")`}`;
  }
  function componentReplacer(str, replaceStr, path) {
    var _a, _b;
    let importName = importsMap.get(path);
    if (!importName)
      importName = ROUTE_IMPORT_NAME.replace("$1", `${importsMap.size}`);
    importsMap.set(path, importName);
    importName = ((_b = (_a = options.resolver.stringify) == null ? void 0 : _a.component) == null ? void 0 : _b.call(_a, importName)) || importName;
    return str.replace(replaceStr, importName);
  }
  function functionReplacer(str, replaceStr, content) {
    if (content.startsWith("function"))
      return str.replace(replaceStr, content);
    if (content.startsWith("_NuFrRa_"))
      return str.replace(replaceStr, content.slice(8));
    return str;
  }
  const stringRoutes = JSON.stringify(preparedRoutes, replaceFunction).replace(componentRE, componentReplacer).replace(hasFunctionRE, functionReplacer);
  const imports = Array.from(importsMap).map((args) => getImportString(...args));
  return {
    imports,
    stringRoutes
  };
}
function generateClientCode(routes, options) {
  var _a, _b;
  const { imports, stringRoutes } = stringifyRoutes(routes, options);
  const code = `${imports.join(";\n")};

const routes = ${stringRoutes};

export default routes;`;
  return ((_b = (_a = options.resolver.stringify) == null ? void 0 : _a.final) == null ? void 0 : _b.call(_a, code)) || code;
}

// src/resolvers/react.ts
function prepareRoutes(routes, options, parent) {
  var _a, _b;
  for (const route of routes) {
    if (parent)
      route.path = (_a = route.path) == null ? void 0 : _a.replace(/^\//, "");
    if (route.children)
      route.children = prepareRoutes(route.children, options, route);
    delete route.rawRoute;
    Object.assign(route, ((_b = options.extendRoute) == null ? void 0 : _b.call(options, route, parent)) || {});
  }
  return routes;
}
async function computeReactRoutes(ctx) {
  var _a, _b;
  const { routeStyle, caseSensitive, importPath } = ctx.options;
  const nuxtStyle = routeStyle === "nuxt";
  const pageRoutes = [...ctx.pageRouteMap.values()].sort((a, b) => countSlash(a.route) - countSlash(b.route));
  const routes = [];
  pageRoutes.forEach((page) => {
    const pathNodes = page.route.split("/");
    const element = importPath === "relative" ? page.path.replace(ctx.root, "") : page.path;
    let parentRoutes = routes;
    for (let i = 0; i < pathNodes.length; i++) {
      const node = pathNodes[i];
      const route = {
        caseSensitive,
        path: "",
        rawRoute: pathNodes.slice(0, i + 1).join("/")
      };
      if (i === pathNodes.length - 1)
        route.element = element;
      const isIndexRoute = normalizeCase(node, caseSensitive).endsWith("index");
      if (!route.path && isIndexRoute) {
        route.path = "/";
      } else if (!isIndexRoute) {
        if (routeStyle === "remix")
          route.path = buildReactRemixRoutePath(node);
        else
          route.path = buildReactRoutePath(node, nuxtStyle);
      }
      const parent = parentRoutes.find((parent2) => {
        return pathNodes.slice(0, i).join("/") === parent2.rawRoute;
      });
      if (parent) {
        parent.children = parent.children || [];
        parentRoutes = parent.children;
      }
      const exits = parentRoutes.some((parent2) => {
        return pathNodes.slice(0, i + 1).join("/") === parent2.rawRoute;
      });
      if (!exits)
        parentRoutes.push(route);
    }
  });
  let finalRoutes = prepareRoutes(routes, ctx.options);
  finalRoutes = await ((_b = (_a = ctx.options).onRoutesGenerated) == null ? void 0 : _b.call(_a, finalRoutes)) || finalRoutes;
  return finalRoutes;
}
async function resolveReactRoutes(ctx) {
  var _a, _b;
  const finalRoutes = await computeReactRoutes(ctx);
  let client = generateClientCode(finalRoutes, ctx.options);
  client = await ((_b = (_a = ctx.options).onClientGenerated) == null ? void 0 : _b.call(_a, client)) || client;
  return client;
}
function reactResolver() {
  return {
    resolveModuleIds() {
      return ["~react-pages", "virtual:generated-pages-react"];
    },
    resolveExtensions() {
      return ["tsx", "jsx", "ts", "js"];
    },
    async resolveRoutes(ctx) {
      return resolveReactRoutes(ctx);
    },
    async getComputedRoutes(ctx) {
      return computeReactRoutes(ctx);
    },
    stringify: {
      component: (path) => `React.createElement(${path})`,
      dynamicImport: (path) => `React.lazy(() => import("${path}"))`,
      final: (code) => `import React from "react";
${code}`
    }
  };
}

// src/resolvers/solid.ts
function prepareRoutes2(options, routes, parent) {
  var _a, _b;
  for (const route of routes) {
    if (parent)
      route.path = (_a = route.path) == null ? void 0 : _a.replace(/^\//, "");
    if (route.children)
      route.children = prepareRoutes2(options, route.children, route);
    delete route.rawRoute;
    Object.assign(route, ((_b = options.extendRoute) == null ? void 0 : _b.call(options, route, parent)) || {});
  }
  return routes;
}
async function computeSolidRoutes(ctx) {
  var _a, _b;
  const { routeStyle, caseSensitive, importPath } = ctx.options;
  const nuxtStyle = routeStyle === "nuxt";
  const pageRoutes = [...ctx.pageRouteMap.values()].sort((a, b) => countSlash(a.route) - countSlash(b.route));
  const routes = [];
  pageRoutes.forEach((page) => {
    const pathNodes = page.route.split("/");
    const component = importPath === "relative" ? page.path.replace(ctx.root, "") : page.path;
    const element = importPath === "relative" ? page.path.replace(ctx.root, "") : page.path;
    let parentRoutes = routes;
    for (let i = 0; i < pathNodes.length; i++) {
      const node = pathNodes[i];
      const normalizedPath = normalizeCase(node, caseSensitive);
      const route = {
        path: "",
        rawRoute: pathNodes.slice(0, i + 1).join("/")
      };
      const parent = parentRoutes.find(
        (parent2) => pathNodes.slice(0, i).join("/") === parent2.rawRoute
      );
      if (parent) {
        parent.children = parent.children || [];
        parentRoutes = parent.children;
      }
      if (i === pathNodes.length - 1) {
        route.element = element;
        route.component = component;
      }
      if (normalizedPath === "index") {
        if (!route.path)
          route.path = "/";
      } else if (normalizedPath !== "index") {
        if (routeStyle === "remix")
          route.path = buildReactRemixRoutePath(node) || "";
        else
          route.path = buildReactRoutePath(node, nuxtStyle) || "";
      }
      const exist = parentRoutes.some((parent2) => {
        return pathNodes.slice(0, i + 1).join("/") === parent2.rawRoute;
      });
      if (!exist)
        parentRoutes.push(route);
    }
  });
  let finalRoutes = prepareRoutes2(ctx.options, routes);
  finalRoutes = await ((_b = (_a = ctx.options).onRoutesGenerated) == null ? void 0 : _b.call(_a, finalRoutes)) || finalRoutes;
  return finalRoutes;
}
async function resolveSolidRoutes(ctx) {
  var _a, _b;
  const finalRoutes = await computeSolidRoutes(ctx);
  let client = generateClientCode(finalRoutes, ctx.options);
  client = await ((_b = (_a = ctx.options).onClientGenerated) == null ? void 0 : _b.call(_a, client)) || client;
  return client;
}
function solidResolver() {
  return {
    resolveModuleIds() {
      return ["~solid-pages"];
    },
    resolveExtensions() {
      return ["tsx", "jsx", "ts", "js"];
    },
    async resolveRoutes(ctx) {
      return resolveSolidRoutes(ctx);
    },
    async getComputedRoutes(ctx) {
      return computeSolidRoutes(ctx);
    },
    stringify: {
      dynamicImport: (path) => `Solid.lazy(() => import("${path}"))`,
      final: (code) => `import * as Solid from "solid-js";
${code}`
    }
  };
}

// src/resolvers/vue.ts
import { dequal } from "dequal";
import colors from "picocolors";

// src/customBlock.ts
import fs from "node:fs";
import extractComments from "extract-comments";
import JSON5 from "json5";
import { importModule } from "local-pkg";
import { parse as YAMLParser } from "yaml";
var routeJSXReg = /^\s+(route)\s+/gm;
function parseJSX(code) {
  return extractComments(code).slice(0, 1).filter((comment) => routeJSXReg.test(comment.value) && comment.value.includes(":") && comment.loc.start.line === 1);
}
function parseYamlComment(code, path) {
  return code.reduce((memo, item) => {
    const { value } = item;
    const v = value.replace(routeJSXReg, "");
    debug.routeBlock(`use ${v} parser`);
    try {
      const yamlResult = YAMLParser(v);
      return __spreadValues(__spreadValues({}, memo), yamlResult);
    } catch (err) {
      throw new Error(`Invalid YAML format of comment in ${path}
${err.message}`);
    }
  }, {});
}
async function parseSFC(code) {
  try {
    const { parse } = await importModule("@vue/compiler-sfc");
    return parse(code, {
      pad: "space"
    }).descriptor || parse({
      source: code
    });
  } catch (e) {
    throw new Error(`[vite-plugin-pages] Vue3's "@vue/compiler-sfc" is required.`);
  }
}
function parseCustomBlock(block, filePath, options) {
  var _a;
  const lang = (_a = block.lang) != null ? _a : options.routeBlockLang;
  debug.routeBlock(`use ${lang} parser`);
  if (lang === "json5") {
    try {
      return JSON5.parse(block.content);
    } catch (err) {
      throw new Error(`Invalid JSON5 format of <${block.type}> content in ${filePath}
${err.message}`);
    }
  } else if (lang === "json") {
    try {
      return JSON.parse(block.content);
    } catch (err) {
      throw new Error(`Invalid JSON format of <${block.type}> content in ${filePath}
${err.message}`);
    }
  } else if (lang === "yaml" || lang === "yml") {
    try {
      return YAMLParser(block.content);
    } catch (err) {
      throw new Error(`Invalid YAML format of <${block.type}> content in ${filePath}
${err.message}`);
    }
  }
}
async function getRouteBlock(path, options) {
  const content = fs.readFileSync(path, "utf8");
  const parsedSFC = await parseSFC(content);
  const blockStr = parsedSFC == null ? void 0 : parsedSFC.customBlocks.find((b) => b.type === "route");
  const parsedJSX = parseJSX(content);
  if (!blockStr && parsedJSX.length === 0)
    return;
  let result;
  if (blockStr)
    result = parseCustomBlock(blockStr, path, options);
  if (parsedJSX.length > 0)
    result = parseYamlComment(parsedJSX, path);
  return result;
}

// src/resolvers/vue.ts
function prepareRoutes3(ctx, routes, parent) {
  var _a, _b, _c, _d;
  for (const route of routes) {
    if (route.name)
      route.name = route.name.replace(new RegExp(`${ctx.options.routeNameSeparator}index$`), "");
    if (parent)
      route.path = (_a = route.path) == null ? void 0 : _a.replace(/^\//, "");
    if (route.children)
      route.children = prepareRoutes3(ctx, route.children, route);
    if ((_b = route.children) == null ? void 0 : _b.find((c) => c.name === route.name))
      delete route.name;
    route.props = true;
    delete route.rawRoute;
    if (route.customBlock) {
      Object.assign(route, route.customBlock || {});
      delete route.customBlock;
    }
    Object.assign(route, ((_d = (_c = ctx.options).extendRoute) == null ? void 0 : _d.call(_c, route, parent)) || {});
  }
  return routes;
}
async function computeVueRoutes(ctx, customBlockMap) {
  var _a, _b;
  const { routeStyle, caseSensitive, importPath, routeNameSeparator } = ctx.options;
  const pageRoutes = [...ctx.pageRouteMap.values()].sort((a, b) => countSlash(a.route) - countSlash(b.route));
  const routes = [];
  pageRoutes.forEach((page) => {
    const pathNodes = page.route.split("/");
    const component = importPath === "relative" ? page.path.replace(ctx.root, "") : page.path;
    const customBlock = customBlockMap.get(page.path);
    const route = {
      name: "",
      path: "",
      component,
      customBlock,
      rawRoute: page.route
    };
    let parentRoutes = routes;
    let dynamicRoute = false;
    for (let i = 0; i < pathNodes.length; i++) {
      const node = pathNodes[i];
      const nuxtStyle = routeStyle === "nuxt";
      const isDynamic = isDynamicRoute(node, nuxtStyle);
      const isCatchAll = isCatchAllRoute(node, nuxtStyle);
      const normalizedName = normalizeName(node, isDynamic, nuxtStyle);
      const normalizedPath = normalizeCase(normalizedName, caseSensitive);
      if (isDynamic)
        dynamicRoute = true;
      route.name += route.name ? `${routeNameSeparator}${normalizedName}` : normalizedName;
      const parent = parentRoutes.find((parent2) => {
        return pathNodes.slice(0, i + 1).join("/") === parent2.rawRoute;
      });
      if (parent) {
        parent.children = parent.children || [];
        parentRoutes = parent.children;
        route.path = "";
      } else if (normalizedPath === "index") {
        if (!route.path)
          route.path = "/";
      } else if (normalizedPath !== "index") {
        if (isDynamic) {
          route.path += `/:${normalizedName}`;
          if (isCatchAll) {
            if (i === 0)
              route.path += "(.*)*";
            else
              route.path += "(.*)";
          } else if (nuxtStyle && i === pathNodes.length - 1) {
            const isIndexFound = pageRoutes.find(({ route: route2 }) => {
              return route2 === page.route.replace(pathNodes[i], "index");
            });
            if (!isIndexFound)
              route.path += "?";
          }
        } else {
          route.path += `/${normalizedPath}`;
        }
      }
    }
    if (dynamicRoute)
      parentRoutes.push(route);
    else
      parentRoutes.unshift(route);
  });
  let finalRoutes = prepareRoutes3(ctx, routes);
  finalRoutes = await ((_b = (_a = ctx.options).onRoutesGenerated) == null ? void 0 : _b.call(_a, finalRoutes)) || finalRoutes;
  return finalRoutes;
}
async function resolveVueRoutes(ctx, customBlockMap) {
  var _a, _b;
  const finalRoutes = await computeVueRoutes(ctx, customBlockMap);
  let client = generateClientCode(finalRoutes, ctx.options);
  client = await ((_b = (_a = ctx.options).onClientGenerated) == null ? void 0 : _b.call(_a, client)) || client;
  return client;
}
function vueResolver() {
  const customBlockMap = /* @__PURE__ */ new Map();
  async function checkCustomBlockChange(ctx, path) {
    var _a;
    const exitsCustomBlock = customBlockMap.get(path);
    let customBlock;
    try {
      customBlock = await getRouteBlock(path, ctx.options);
    } catch (error) {
      (_a = ctx.logger) == null ? void 0 : _a.error(colors.red(`[vite-plugin-pages] ${error.message}`));
      return;
    }
    if (!exitsCustomBlock && !customBlock)
      return;
    if (!customBlock) {
      customBlockMap.delete(path);
      ctx.debug.routeBlock("%s deleted", path);
      return;
    }
    if (!exitsCustomBlock || !dequal(exitsCustomBlock, customBlock)) {
      ctx.debug.routeBlock("%s old: %O", path, exitsCustomBlock);
      ctx.debug.routeBlock("%s new: %O", path, customBlock);
      customBlockMap.set(path, customBlock);
      ctx.onUpdate();
    }
  }
  return {
    resolveExtensions() {
      return ["vue", "ts", "js"];
    },
    resolveModuleIds() {
      return ["~pages", "pages-generated", "virtual:generated-pages"];
    },
    async resolveRoutes(ctx) {
      return resolveVueRoutes(ctx, customBlockMap);
    },
    async getComputedRoutes(ctx) {
      return computeVueRoutes(ctx, customBlockMap);
    },
    hmr: {
      added: async (ctx, path) => checkCustomBlockChange(ctx, path),
      changed: async (ctx, path) => checkCustomBlockChange(ctx, path),
      removed: async (_ctx, path) => {
        customBlockMap.delete(path);
      }
    }
  };
}

// src/options.ts
function resolvePageDirs(dirs, root, exclude) {
  dirs = toArray(dirs);
  return dirs.flatMap((dir) => {
    const option = typeof dir === "string" ? { dir, baseRoute: "" } : dir;
    option.dir = slash(resolve2(root, option.dir)).replace(`${root}/`, "");
    option.baseRoute = option.baseRoute.replace(/^\//, "").replace(/\/$/, "");
    return getPageDirs(option, root, exclude);
  });
}
var syncIndexResolver = (filepath, options) => {
  for (const page of options.dirs) {
    if (page.baseRoute === "" && filepath.startsWith(`/${page.dir}/index`))
      return "sync";
  }
  return "async";
};
function getResolver(originalResolver) {
  let resolver = originalResolver || "vue";
  if (typeof resolver !== "string")
    return resolver;
  switch (resolver) {
    case "vue":
      resolver = vueResolver();
      break;
    case "react":
      resolver = reactResolver();
      break;
    case "solid":
      resolver = solidResolver();
      break;
    default:
      throw new Error(`Unsupported resolver: ${resolver}`);
  }
  return resolver;
}
function resolveOptions(userOptions, viteRoot) {
  var _a;
  const {
    dirs = ["src/pages"],
    routeBlockLang = "json5",
    exclude = ["node_modules", ".git", "**/__*__/**"],
    caseSensitive = false,
    routeNameSeparator = "-",
    extendRoute,
    onRoutesGenerated,
    onClientGenerated
  } = userOptions;
  const root = viteRoot || slash(process.cwd());
  const importMode = userOptions.importMode || syncIndexResolver;
  const importPath = userOptions.importPath || "relative";
  const resolver = getResolver(userOptions.resolver);
  const extensions = userOptions.extensions || resolver.resolveExtensions();
  const extensionsRE = new RegExp(`\\.(${extensions.join("|")})$`);
  const resolvedDirs = resolvePageDirs(dirs, root, exclude);
  const routeStyle = userOptions.routeStyle || "next";
  const moduleIds = userOptions.moduleId ? [userOptions.moduleId] : ((_a = resolver.resolveModuleIds) == null ? void 0 : _a.call(resolver)) || MODULE_IDS;
  const resolvedOptions = {
    dirs: resolvedDirs,
    routeStyle,
    routeBlockLang,
    moduleIds,
    root,
    extensions,
    importMode,
    importPath,
    exclude,
    caseSensitive,
    resolver,
    extensionsRE,
    extendRoute,
    onRoutesGenerated,
    onClientGenerated,
    routeNameSeparator
  };
  return resolvedOptions;
}

// src/context.ts
var PageContext = class {
  constructor(userOptions, viteRoot = process2.cwd()) {
    this._pageRouteMap = /* @__PURE__ */ new Map();
    this.rawOptions = userOptions;
    this.root = slash(viteRoot);
    debug.env("root", this.root);
    this.options = resolveOptions(userOptions, this.root);
    debug.options(this.options);
  }
  setLogger(logger) {
    this.logger = logger;
  }
  setupViteServer(server) {
    if (this._server === server)
      return;
    this._server = server;
    this.setupWatcher(server.watcher);
  }
  setupWatcher(watcher) {
    watcher.on("unlink", async (path) => {
      path = slash(path);
      if (!isTarget(path, this.options))
        return;
      await this.removePage(path);
      this.onUpdate();
    });
    watcher.on("add", async (path) => {
      path = slash(path);
      if (!isTarget(path, this.options))
        return;
      const page = this.options.dirs.find((i) => path.startsWith(slash(resolve3(this.root, i.dir))));
      await this.addPage(path, page);
      this.onUpdate();
    });
    watcher.on("change", async (path) => {
      var _a, _b;
      path = slash(path);
      if (!isTarget(path, this.options))
        return;
      const page = this._pageRouteMap.get(path);
      if (page)
        await ((_b = (_a = this.options.resolver.hmr) == null ? void 0 : _a.changed) == null ? void 0 : _b.call(_a, this, path));
    });
  }
  async addPage(path, pageDir) {
    var _a, _b;
    debug.pages("add", path);
    for (const p of toArray(path)) {
      const pageDirPath = slash(resolve3(this.root, pageDir.dir));
      const extension = this.options.extensions.find((ext) => p.endsWith(`.${ext}`));
      if (!extension)
        continue;
      const route = slash(join2(pageDir.baseRoute, p.replace(`${pageDirPath}/`, "").replace(`.${extension}`, "")));
      this._pageRouteMap.set(p, {
        path: p,
        route
      });
      await ((_b = (_a = this.options.resolver.hmr) == null ? void 0 : _a.added) == null ? void 0 : _b.call(_a, this, p));
    }
  }
  async removePage(path) {
    var _a, _b;
    debug.pages("remove", path);
    this._pageRouteMap.delete(path);
    await ((_b = (_a = this.options.resolver.hmr) == null ? void 0 : _a.removed) == null ? void 0 : _b.call(_a, this, path));
  }
  onUpdate() {
    if (!this._server)
      return;
    invalidatePagesModule(this._server);
    debug.hmr("Reload generated pages.");
    this._server.ws.send({
      type: "full-reload"
    });
  }
  async resolveRoutes() {
    return this.options.resolver.resolveRoutes(this);
  }
  async searchGlob() {
    const pageDirFiles = this.options.dirs.map((page) => {
      const pagesDirPath = slash(resolve3(this.options.root, page.dir));
      const files = getPageFiles(pagesDirPath, this.options, page);
      debug.search(page.dir, files);
      return __spreadProps(__spreadValues({}, page), {
        files: files.map((file) => slash(file))
      });
    });
    for (const page of pageDirFiles)
      await this.addPage(page.files, page);
    debug.cache(this.pageRouteMap);
  }
  get debug() {
    return debug;
  }
  get pageRouteMap() {
    return this._pageRouteMap;
  }
};

// src/index.ts
function pagesPlugin(userOptions = {}) {
  let ctx;
  return {
    name: "vite-plugin-pages",
    enforce: "pre",
    async configResolved(config) {
      if (!userOptions.resolver && config.plugins.find((i) => i.name.includes("vite:react"))) {
        userOptions.resolver = "react";
      }
      if (!userOptions.resolver && config.plugins.find((i) => i.name.includes("solid"))) {
        userOptions.resolver = "solid";
      }
      ctx = new PageContext(userOptions, config.root);
      ctx.setLogger(config.logger);
      await ctx.searchGlob();
    },
    api: {
      getResolvedRoutes() {
        return ctx.options.resolver.getComputedRoutes(ctx);
      }
    },
    configureServer(server) {
      ctx.setupViteServer(server);
    },
    resolveId(id) {
      if (ctx.options.moduleIds.includes(id))
        return `${MODULE_ID_VIRTUAL}?id=${id}`;
      if (routeBlockQueryRE.test(id))
        return ROUTE_BLOCK_ID_VIRTUAL;
      return null;
    },
    async load(id) {
      const {
        moduleId,
        pageId
      } = parsePageRequest(id);
      if (moduleId === MODULE_ID_VIRTUAL && pageId && ctx.options.moduleIds.includes(pageId))
        return ctx.resolveRoutes();
      if (id === ROUTE_BLOCK_ID_VIRTUAL) {
        return {
          code: "export default {};",
          map: null
        };
      }
      return null;
    }
  };
}
var index_default = pagesPlugin;
export {
  PageContext,
  index_default as default,
  reactResolver,
  solidResolver,
  syncIndexResolver,
  vueResolver
};
//# sourceMappingURL=index.js.map