#!/usr/bin/env node
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __esm = (fn, res) => function __init() {
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
};
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};

// src/build/route-types/param-extraction.ts
function extractParamsFromPattern(pattern) {
  const params = {};
  const regex = /:([a-zA-Z_$][\w$]*)(?:\([^)]+\))?(\?)?/g;
  let match;
  while ((match = regex.exec(pattern)) !== null) {
    params[match[1]] = match[2] ? "string?" : "string";
  }
  return Object.keys(params).length > 0 ? params : void 0;
}
function formatRouteEntry(key, pattern, _params, search) {
  const hasSearch = search && Object.keys(search).length > 0;
  if (!hasSearch) {
    return `  ${key}: "${pattern}",`;
  }
  const searchBody = Object.entries(search).map(([k, v]) => `${k}: "${v}"`).join(", ");
  return `  ${key}: { path: "${pattern}", search: { ${searchBody} } },`;
}
var init_param_extraction = __esm({
  "src/build/route-types/param-extraction.ts"() {
    "use strict";
  }
});

// src/build/route-types/ast-helpers.ts
import ts from "typescript";
function getStringValue(node) {
  if (ts.isStringLiteral(node)) return node.text;
  if (ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
  return null;
}
function extractObjectStringProperties(node) {
  const result = {};
  for (const prop of node.properties) {
    if (!ts.isPropertyAssignment(prop)) continue;
    const key = ts.isIdentifier(prop.name) ? prop.name.text : ts.isStringLiteral(prop.name) ? prop.name.text : null;
    if (!key) continue;
    const val = getStringValue(prop.initializer);
    if (val !== null) result[key] = val;
  }
  return result;
}
var init_ast_helpers = __esm({
  "src/build/route-types/ast-helpers.ts"() {
    "use strict";
  }
});

// src/build/route-types/ast-route-extraction.ts
import ts2 from "typescript";
function extractRoutesFromSource(code) {
  const sourceFile = ts2.createSourceFile(
    "input.tsx",
    code,
    ts2.ScriptTarget.Latest,
    true,
    ts2.ScriptKind.TSX
  );
  const routes = [];
  function visit(node) {
    if (ts2.isCallExpression(node)) {
      const callee = node.expression;
      const isPath = ts2.isIdentifier(callee) && callee.text === "path" || ts2.isPropertyAccessExpression(callee) && ts2.isIdentifier(callee.expression) && callee.expression.text === "path";
      if (isPath && node.arguments.length >= 1) {
        const route = extractRouteFromCallExpression(node);
        if (route) routes.push(route);
      }
    }
    ts2.forEachChild(node, visit);
  }
  visit(sourceFile);
  return routes;
}
function extractRouteFromCallExpression(node) {
  const patternNode = node.arguments[0];
  const pattern = getStringValue(patternNode);
  if (pattern === null) return null;
  let name = null;
  let search;
  for (let i = 1; i < node.arguments.length; i++) {
    const arg = node.arguments[i];
    if (ts2.isObjectLiteralExpression(arg)) {
      for (const prop of arg.properties) {
        if (!ts2.isPropertyAssignment(prop)) continue;
        const propName = ts2.isIdentifier(prop.name) ? prop.name.text : null;
        if (propName === "name") {
          name = getStringValue(prop.initializer);
        } else if (propName === "search" && ts2.isObjectLiteralExpression(prop.initializer)) {
          search = extractObjectStringProperties(prop.initializer);
        }
      }
    }
  }
  if (!name) return null;
  const params = extractParamsFromPattern(pattern);
  return {
    name,
    pattern,
    ...params ? { params } : {},
    ...search && Object.keys(search).length > 0 ? { search } : {}
  };
}
var init_ast_route_extraction = __esm({
  "src/build/route-types/ast-route-extraction.ts"() {
    "use strict";
    init_ast_helpers();
    init_param_extraction();
  }
});

// src/route-name.ts
function isAutoGeneratedRouteName(name) {
  return name.split(".").some((segment) => {
    return segment.startsWith(AUTO_GENERATED_ROUTE_PREFIX) || segment.startsWith(INTERNAL_INCLUDE_SCOPE_PREFIX);
  });
}
var AUTO_GENERATED_ROUTE_PREFIX, INTERNAL_INCLUDE_SCOPE_PREFIX;
var init_route_name = __esm({
  "src/route-name.ts"() {
    "use strict";
    AUTO_GENERATED_ROUTE_PREFIX = "$path_";
    INTERNAL_INCLUDE_SCOPE_PREFIX = "$prefix_";
  }
});

// src/build/route-types/codegen.ts
function generatePerModuleTypesSource(routes) {
  const valid = routes.filter(({ name }) => {
    if (!name || /["'\\`\n\r]/.test(name)) {
      console.warn(
        `[rango] Skipping route with invalid name: ${JSON.stringify(name)}`
      );
      return false;
    }
    return true;
  });
  const deduped = /* @__PURE__ */ new Map();
  for (const { name, pattern, params, search } of valid) {
    if (deduped.has(name)) {
      console.warn(
        `[rango] Duplicate route name "${name}" \u2014 keeping first definition`
      );
      continue;
    }
    deduped.set(name, { pattern, params, search });
  }
  const sorted = [...deduped.entries()].sort(([a], [b]) => a.localeCompare(b));
  const body = sorted.map(([name, { pattern, params, search }]) => {
    const key = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `"${name}"`;
    return formatRouteEntry(key, pattern, params, search);
  }).join("\n");
  return `// Auto-generated by @rangojs/router - do not edit
export const routes = {
${body}
} as const;
export type routes = typeof routes;
`;
}
function generateRouteTypesSource(routeManifest, searchSchemas) {
  const entries = Object.entries(routeManifest).filter(([name]) => !isAutoGeneratedRouteName(name)).sort(([a], [b]) => a.localeCompare(b));
  const filteredSearchSchemas = searchSchemas ? Object.fromEntries(
    Object.entries(searchSchemas).filter(
      ([name]) => !isAutoGeneratedRouteName(name)
    )
  ) : void 0;
  const objectBody = entries.map(([name, pattern]) => {
    const key = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `"${name}"`;
    const params = extractParamsFromPattern(pattern);
    const search = filteredSearchSchemas?.[name];
    return formatRouteEntry(key, pattern, params, search);
  }).join("\n");
  return `// Auto-generated by @rangojs/router - do not edit
export const NamedRoutes = {
${objectBody}
} as const;

declare global {
  namespace Rango {
    interface GeneratedRouteMap extends Readonly<typeof NamedRoutes> {}
  }
}
`;
}
var init_codegen = __esm({
  "src/build/route-types/codegen.ts"() {
    "use strict";
    init_param_extraction();
    init_route_name();
  }
});

// src/build/route-types/scan-filter.ts
import { join, relative } from "node:path";
import { readdirSync } from "node:fs";
import picomatch from "picomatch";
function findTsFiles(dir, filter) {
  const results = [];
  let entries;
  try {
    entries = readdirSync(dir, { withFileTypes: true });
  } catch (err) {
    console.warn(
      `[rango] Failed to scan directory ${dir}: ${err.message}`
    );
    return results;
  }
  for (const entry of entries) {
    const fullPath = join(dir, entry.name);
    if (entry.isDirectory()) {
      if (entry.name === "node_modules" || entry.name.startsWith(".") || entry.name === "dist" || entry.name === "build" || entry.name === "coverage")
        continue;
      results.push(...findTsFiles(fullPath, filter));
    } else if ((entry.name.endsWith(".ts") || entry.name.endsWith(".tsx") || entry.name.endsWith(".js") || entry.name.endsWith(".jsx")) && !entry.name.includes(".gen.")) {
      if (filter && !filter(fullPath)) continue;
      results.push(fullPath);
    }
  }
  return results;
}
var init_scan_filter = __esm({
  "src/build/route-types/scan-filter.ts"() {
    "use strict";
  }
});

// src/build/route-types/include-resolution.ts
import { readFileSync, existsSync } from "node:fs";
import { dirname, resolve } from "node:path";
import ts3 from "typescript";
function extractNamePrefixFromInclude(node) {
  if (node.arguments.length >= 3) {
    const thirdArg = node.arguments[2];
    if (ts3.isObjectLiteralExpression(thirdArg)) {
      for (const prop of thirdArg.properties) {
        if (!ts3.isPropertyAssignment(prop)) continue;
        const propName = ts3.isIdentifier(prop.name) ? prop.name.text : null;
        if (propName === "name") {
          return getStringValue(prop.initializer);
        }
      }
    }
  }
  return null;
}
function extractIncludesWithDiagnostics(code) {
  const sourceFile = ts3.createSourceFile(
    "input.tsx",
    code,
    ts3.ScriptTarget.Latest,
    true,
    ts3.ScriptKind.TSX
  );
  const resolved = [];
  const unresolvable = [];
  function visit(node) {
    if (ts3.isCallExpression(node)) {
      const callee = node.expression;
      if (ts3.isIdentifier(callee) && callee.text === "include") {
        if (node.arguments.length < 2) {
          ts3.forEachChild(node, visit);
          return;
        }
        const pathPrefix = getStringValue(node.arguments[0]);
        if (pathPrefix === null) {
          ts3.forEachChild(node, visit);
          return;
        }
        const secondArg = node.arguments[1];
        const namePrefix = extractNamePrefixFromInclude(node);
        if (ts3.isIdentifier(secondArg)) {
          resolved.push({
            pathPrefix,
            variableName: secondArg.text,
            namePrefix
          });
        } else if (ts3.isCallExpression(secondArg)) {
          const callText = secondArg.expression.getText(sourceFile);
          unresolvable.push({
            pathPrefix,
            namePrefix,
            reason: "factory-call",
            detail: `${callText}()`
          });
        } else {
          unresolvable.push({
            pathPrefix,
            namePrefix,
            reason: "dynamic-expression",
            detail: secondArg.getText(sourceFile)
          });
        }
      }
    }
    ts3.forEachChild(node, visit);
  }
  visit(sourceFile);
  return { resolved, unresolvable };
}
function resolveImportedVariable(code, localName) {
  const importRegex = /import\s*\{([^}]+)\}\s*from\s*["']([^"']+)["']/g;
  let match;
  while ((match = importRegex.exec(code)) !== null) {
    const imports = match[1];
    const specifier = match[2];
    const parts = imports.split(",").map((s) => s.trim()).filter(Boolean);
    for (const part of parts) {
      const asMatch = part.match(/^(\w+)\s+as\s+(\w+)$/);
      if (asMatch && asMatch[2] === localName)
        return { specifier, exportedName: asMatch[1] };
      if (part === localName) return { specifier, exportedName: localName };
    }
  }
  return null;
}
function resolveImportPath(importSpec, fromFile) {
  if (!importSpec.startsWith(".")) return null;
  const dir = dirname(fromFile);
  let base = importSpec;
  if (base.endsWith(".js")) base = base.slice(0, -3);
  else if (base.endsWith(".mjs")) base = base.slice(0, -4);
  else if (base.endsWith(".jsx")) base = base.slice(0, -4);
  const candidates = [
    resolve(dir, base + ".ts"),
    resolve(dir, base + ".tsx"),
    resolve(dir, base + ".js"),
    resolve(dir, base + ".jsx"),
    resolve(dir, base + "/index.ts"),
    resolve(dir, base + "/index.tsx"),
    resolve(dir, base + "/index.js"),
    resolve(dir, base + "/index.jsx")
  ];
  for (const candidate of candidates) {
    if (existsSync(candidate)) return candidate;
  }
  return null;
}
function extractUrlsBlockForVariable(code, varName) {
  const sourceFile = ts3.createSourceFile(
    "input.tsx",
    code,
    ts3.ScriptTarget.Latest,
    true,
    ts3.ScriptKind.TSX
  );
  let result = null;
  function visit(node) {
    if (result) return;
    if (ts3.isVariableDeclaration(node) && ts3.isIdentifier(node.name) && node.name.text === varName && node.initializer && ts3.isCallExpression(node.initializer)) {
      const callee = node.initializer.expression;
      if (ts3.isIdentifier(callee) && callee.text === "urls") {
        result = node.initializer.getText(sourceFile);
        return;
      }
    }
    ts3.forEachChild(node, visit);
  }
  visit(sourceFile);
  return result;
}
function buildRouteMapFromBlock(block, fullSource, filePath, visited, searchSchemasOut, diagnosticsOut) {
  const routeMap = {};
  const localRoutes = extractRoutesFromSource(block);
  for (const { name, pattern, search } of localRoutes) {
    routeMap[name] = pattern;
    if (search && searchSchemasOut) {
      searchSchemasOut[name] = search;
    }
  }
  const { resolved: includes, unresolvable } = extractIncludesWithDiagnostics(block);
  if (diagnosticsOut) {
    for (const entry of unresolvable) {
      diagnosticsOut.push({ ...entry, sourceFile: filePath });
    }
  }
  for (const { pathPrefix, variableName, namePrefix } of includes) {
    let childResult;
    const imported = resolveImportedVariable(fullSource, variableName);
    if (imported) {
      const targetFile = resolveImportPath(imported.specifier, filePath);
      if (!targetFile) {
        if (diagnosticsOut) {
          diagnosticsOut.push({
            pathPrefix,
            namePrefix,
            reason: "file-not-found",
            sourceFile: filePath,
            detail: `import "${imported.specifier}" resolved to no file`
          });
        }
        continue;
      }
      childResult = buildCombinedRouteMapWithSearch(
        targetFile,
        imported.exportedName,
        visited,
        diagnosticsOut
      );
    } else {
      const sameFileBlock = extractUrlsBlockForVariable(
        fullSource,
        variableName
      );
      if (!sameFileBlock) {
        if (diagnosticsOut) {
          diagnosticsOut.push({
            pathPrefix,
            namePrefix,
            reason: "unresolvable-import",
            sourceFile: filePath,
            detail: `variable "${variableName}" not found in imports or same-file scope`
          });
        }
        continue;
      }
      childResult = buildCombinedRouteMapWithSearch(
        filePath,
        variableName,
        visited,
        diagnosticsOut
      );
    }
    if (namePrefix === null) {
      continue;
    }
    for (const [name, pattern] of Object.entries(childResult.routes)) {
      const prefixedName = namePrefix ? `${namePrefix}.${name}` : name;
      let prefixedPattern;
      if (pattern === "/") {
        prefixedPattern = pathPrefix || "/";
      } else if (pathPrefix.endsWith("/") && pattern.startsWith("/")) {
        prefixedPattern = pathPrefix + pattern.slice(1);
      } else {
        prefixedPattern = pathPrefix + pattern;
      }
      routeMap[prefixedName] = prefixedPattern;
      if (childResult.searchSchemas[name] && searchSchemasOut) {
        searchSchemasOut[prefixedName] = childResult.searchSchemas[name];
      }
    }
  }
  return routeMap;
}
function buildCombinedRouteMapWithSearch(filePath, variableName, visited, diagnosticsOut, inlineBlock) {
  visited = visited ?? /* @__PURE__ */ new Set();
  const realPath = resolve(filePath);
  const key = variableName ? `${realPath}:${variableName}` : realPath;
  if (visited.has(key)) {
    console.warn(`[rango] Circular include detected, skipping: ${key}`);
    return { routes: {}, searchSchemas: {} };
  }
  visited.add(key);
  let source;
  try {
    source = readFileSync(realPath, "utf-8");
  } catch {
    return { routes: {}, searchSchemas: {} };
  }
  let block;
  if (inlineBlock) {
    block = inlineBlock;
  } else if (variableName) {
    const extracted = extractUrlsBlockForVariable(source, variableName);
    if (!extracted) return { routes: {}, searchSchemas: {} };
    block = extracted;
  } else {
    block = source;
  }
  const searchSchemas = {};
  const routes = buildRouteMapFromBlock(
    block,
    source,
    realPath,
    visited,
    searchSchemas,
    diagnosticsOut
  );
  visited.delete(key);
  return { routes, searchSchemas };
}
var init_include_resolution = __esm({
  "src/build/route-types/include-resolution.ts"() {
    "use strict";
    init_ast_helpers();
    init_ast_route_extraction();
  }
});

// src/build/route-types/per-module-writer.ts
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2 } from "node:fs";
import ts4 from "typescript";
function findUrlsVariableNames(code) {
  const sourceFile = ts4.createSourceFile(
    "input.tsx",
    code,
    ts4.ScriptTarget.Latest,
    true,
    ts4.ScriptKind.TSX
  );
  const names = [];
  function visit(node) {
    if (ts4.isVariableDeclaration(node) && ts4.isIdentifier(node.name) && node.initializer && ts4.isCallExpression(node.initializer)) {
      const callee = node.initializer.expression;
      if (ts4.isIdentifier(callee) && callee.text === "urls") {
        names.push(node.name.text);
      }
    }
    ts4.forEachChild(node, visit);
  }
  visit(sourceFile);
  return names;
}
function writePerModuleRouteTypesForFile(filePath) {
  try {
    const source = readFileSync2(filePath, "utf-8");
    if (!source.includes("urls(")) return;
    const varNames = findUrlsVariableNames(source);
    let routes;
    if (varNames.length > 0) {
      routes = [];
      for (const varName of varNames) {
        const { routes: routeMap, searchSchemas } = buildCombinedRouteMapWithSearch(filePath, varName);
        for (const [name, pattern] of Object.entries(routeMap)) {
          const params = extractParamsFromPattern(pattern);
          routes.push({
            name,
            pattern,
            ...params ? { params } : {},
            ...searchSchemas[name] ? { search: searchSchemas[name] } : {}
          });
        }
      }
    } else {
      routes = extractRoutesFromSource(source);
    }
    const genPath = filePath.replace(/\.(tsx?|jsx?)$/, ".gen.ts");
    if (routes.length === 0) {
      if (varNames.length > 0 && !existsSync2(genPath)) {
        writeFileSync(genPath, generatePerModuleTypesSource([]));
        console.log(
          `[rango] Generated route types (placeholder) -> ${genPath}`
        );
      }
      return;
    }
    const genSource = generatePerModuleTypesSource(routes);
    const existing = existsSync2(genPath) ? readFileSync2(genPath, "utf-8") : null;
    if (existing !== genSource) {
      writeFileSync(genPath, genSource);
      console.log(`[rango] Generated route types -> ${genPath}`);
    }
  } catch (err) {
    console.warn(
      `[rango] Failed to generate route types for ${filePath}: ${err.message}`
    );
  }
}
var init_per_module_writer = __esm({
  "src/build/route-types/per-module-writer.ts"() {
    "use strict";
    init_param_extraction();
    init_ast_route_extraction();
    init_codegen();
    init_include_resolution();
    init_scan_filter();
  }
});

// src/build/route-types/source-scan.ts
function isLineTerminator(ch) {
  const c = ch.charCodeAt(0);
  return c === 10 || c === 13 || c === 8232 || c === 8233;
}
function makeCodeClassifier(code) {
  const n = code.length;
  let i = 0;
  let skipStart = -1;
  let skipEnd = -1;
  return (q) => {
    if (q >= skipStart && q < skipEnd) return false;
    while (i < n && i <= q) {
      const c = code[i];
      const d = i + 1 < n ? code[i + 1] : "";
      let end = -1;
      if (c === "/" && d === "/") {
        let j = i + 2;
        while (j < n && !isLineTerminator(code[j])) j++;
        end = j;
      } else if (c === "/" && d === "*") {
        let j = i + 2;
        while (j < n && !(code[j] === "*" && code[j + 1] === "/")) j++;
        end = Math.min(n, j + 2);
      } else if (c === '"' || c === "'" || c === "`") {
        let j = i + 1;
        while (j < n) {
          if (code[j] === "\\") {
            j += 2;
            continue;
          }
          if (code[j] === c) {
            j++;
            break;
          }
          j++;
        }
        end = j;
      }
      if (end >= 0) {
        if (q < end) {
          skipStart = i;
          skipEnd = end;
          return false;
        }
        i = end;
      } else {
        i++;
      }
    }
    return true;
  };
}
function firstCodeMatchIndex(code, pattern) {
  const inCode = makeCodeClassifier(code);
  pattern.lastIndex = 0;
  let m;
  while ((m = pattern.exec(code)) !== null) {
    if (inCode(m.index)) return m.index;
    if (pattern.lastIndex <= m.index) pattern.lastIndex = m.index + 1;
  }
  return -1;
}
var init_source_scan = __esm({
  "src/build/route-types/source-scan.ts"() {
    "use strict";
  }
});

// src/build/route-types/router-processing.ts
import {
  readFileSync as readFileSync3,
  writeFileSync as writeFileSync2,
  existsSync as existsSync3,
  unlinkSync,
  readdirSync as readdirSync2
} from "node:fs";
import {
  join as join2,
  dirname as dirname2,
  resolve as resolve2,
  sep,
  basename as pathBasename
} from "node:path";
import ts5 from "typescript";
function countPublicRouteEntries(source) {
  const matches = source.matchAll(/^\s+(?:"([^"]+)"|([a-zA-Z_$][^:]*)):\s*["{]/gm) ?? [];
  let count = 0;
  for (const match of matches) {
    const routeName = match[1] || match[2];
    if (routeName && !isAutoGeneratedRouteName(routeName.trim())) {
      count++;
    }
  }
  return count;
}
function isRoutableSourceFile(name) {
  return (name.endsWith(".ts") || name.endsWith(".tsx") || name.endsWith(".js") || name.endsWith(".jsx")) && !name.includes(".gen.") && !name.includes(".test.") && !name.includes(".spec.");
}
function findRouterFilesRecursive(dir, filter, results) {
  let entries;
  try {
    entries = readdirSync2(dir, { withFileTypes: true });
  } catch (err) {
    console.warn(
      `[rango] Failed to scan directory ${dir}: ${err.message}`
    );
    return;
  }
  const childDirs = [];
  const routerFilesInDir = [];
  for (const entry of entries) {
    const fullPath = join2(dir, entry.name);
    if (entry.isDirectory()) {
      if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "coverage" || entry.name === "__tests__" || entry.name === "__mocks__" || entry.name.startsWith("."))
        continue;
      childDirs.push(fullPath);
      continue;
    }
    if (!isRoutableSourceFile(entry.name)) continue;
    if (filter && !filter(fullPath)) continue;
    try {
      const source = readFileSync3(fullPath, "utf-8");
      if (ROUTER_CALL_PATTERN.test(source) && firstCodeMatchIndex(source, ROUTER_CALL_PATTERN_G) >= 0) {
        routerFilesInDir.push(fullPath);
      }
    } catch {
      continue;
    }
  }
  if (routerFilesInDir.length > 0) {
    results.push(...routerFilesInDir);
    return;
  }
  for (const childDir of childDirs) {
    findRouterFilesRecursive(childDir, filter, results);
  }
}
function findNestedRouterConflict(routerFiles) {
  const routerDirs = [
    ...new Set(routerFiles.map((filePath) => dirname2(resolve2(filePath))))
  ].sort((a, b) => a.length - b.length);
  for (let i = 0; i < routerDirs.length; i++) {
    const ancestorDir = routerDirs[i];
    const prefix = ancestorDir.endsWith(sep) ? ancestorDir : `${ancestorDir}${sep}`;
    for (let j = i + 1; j < routerDirs.length; j++) {
      const nestedDir = routerDirs[j];
      if (!nestedDir.startsWith(prefix)) continue;
      const ancestorFile = routerFiles.find(
        (filePath) => dirname2(resolve2(filePath)) === ancestorDir
      );
      const nestedFile = routerFiles.find(
        (filePath) => dirname2(resolve2(filePath)) === nestedDir
      );
      if (ancestorFile && nestedFile) {
        return { ancestor: ancestorFile, nested: nestedFile };
      }
    }
  }
  return null;
}
function formatNestedRouterConflictError(conflict, prefix = "[rango]") {
  return `${prefix} Nested router roots are not supported.
Router root: ${conflict.ancestor}
Nested router: ${conflict.nested}
Move the nested router into a sibling directory or configure it as a separate app root.`;
}
function extractUrlsFromRouter(code) {
  const sourceFile = ts5.createSourceFile(
    "router.tsx",
    code,
    ts5.ScriptTarget.Latest,
    true,
    ts5.ScriptKind.TSX
  );
  let result = null;
  function isCreateRouterCall(node) {
    if (!ts5.isCallExpression(node)) return false;
    const callee = node.expression;
    return ts5.isIdentifier(callee) && callee.text === "createRouter";
  }
  function isInlineBuilder(node) {
    return ts5.isArrowFunction(node) || ts5.isFunctionExpression(node);
  }
  function isRoutesOnCreateRouter(node) {
    if (!ts5.isPropertyAccessExpression(node.expression) || node.expression.name.text !== "routes")
      return false;
    let inner = node.expression.expression;
    while (ts5.isCallExpression(inner) && ts5.isPropertyAccessExpression(inner.expression)) {
      inner = inner.expression.expression;
    }
    return isCreateRouterCall(inner);
  }
  function visit(node) {
    if (result) return;
    if (ts5.isCallExpression(node) && node.arguments.length >= 1 && isRoutesOnCreateRouter(node)) {
      const arg = node.arguments[0];
      if (ts5.isIdentifier(arg)) {
        result = { kind: "variable", name: arg.text };
      } else if (isInlineBuilder(arg)) {
        result = { kind: "inline", block: arg.getText(sourceFile) };
      }
      return;
    }
    if (isCreateRouterCall(node)) {
      const callExpr = node;
      for (const callArg of callExpr.arguments) {
        if (ts5.isObjectLiteralExpression(callArg)) {
          for (const prop of callArg.properties) {
            if (ts5.isPropertyAssignment(prop) && ts5.isIdentifier(prop.name) && prop.name.text === "urls") {
              if (ts5.isIdentifier(prop.initializer)) {
                result = { kind: "variable", name: prop.initializer.text };
              } else if (isInlineBuilder(prop.initializer)) {
                result = {
                  kind: "inline",
                  block: prop.initializer.getText(sourceFile)
                };
              }
              return;
            }
          }
        }
      }
    }
    ts5.forEachChild(node, visit);
  }
  visit(sourceFile);
  return result;
}
function extractBasenameFromRouter(code) {
  const sourceFile = ts5.createSourceFile(
    "router.tsx",
    code,
    ts5.ScriptTarget.Latest,
    true,
    ts5.ScriptKind.TSX
  );
  let result;
  function visit(node) {
    if (result !== void 0) return;
    if (ts5.isCallExpression(node) && ts5.isIdentifier(node.expression) && node.expression.text === "createRouter") {
      for (const arg of node.arguments) {
        if (ts5.isObjectLiteralExpression(arg)) {
          for (const prop of arg.properties) {
            if (ts5.isPropertyAssignment(prop) && ts5.isIdentifier(prop.name) && prop.name.text === "basename" && ts5.isStringLiteral(prop.initializer)) {
              result = prop.initializer.text;
              return;
            }
          }
        }
      }
    }
    ts5.forEachChild(node, visit);
  }
  visit(sourceFile);
  return result;
}
function applyBasenameToRoutes(result, basename) {
  const prefixed = {};
  for (const [name, pattern] of Object.entries(result.routes)) {
    if (pattern === "/") {
      prefixed[name] = basename;
    } else if (basename.endsWith("/") && pattern.startsWith("/")) {
      prefixed[name] = basename + pattern.slice(1);
    } else {
      prefixed[name] = basename + pattern;
    }
  }
  return { routes: prefixed, searchSchemas: result.searchSchemas };
}
function genFileTsPath(sourceFile) {
  const base = pathBasename(sourceFile).replace(/\.(tsx?|jsx?)$/, "");
  return join2(dirname2(sourceFile), `${base}.named-routes.gen.ts`);
}
function resolveSearchSchemas(publicRouteNames, runtimeSchemas, sourceFile) {
  if (runtimeSchemas && Object.keys(runtimeSchemas).length > 0) {
    return runtimeSchemas;
  }
  const staticParsed = buildCombinedRouteMapForRouterFile(sourceFile);
  if (Object.keys(staticParsed.searchSchemas).length === 0) {
    return runtimeSchemas;
  }
  const filtered = {};
  for (const name of publicRouteNames) {
    const schema = staticParsed.searchSchemas[name];
    if (schema) filtered[name] = schema;
  }
  return Object.keys(filtered).length > 0 ? filtered : runtimeSchemas;
}
function buildCombinedRouteMapForRouterFile(routerFilePath) {
  let routerSource;
  try {
    routerSource = readFileSync3(routerFilePath, "utf-8");
  } catch {
    return { routes: {}, searchSchemas: {} };
  }
  const extraction = extractUrlsFromRouter(routerSource);
  if (!extraction) {
    return { routes: {}, searchSchemas: {} };
  }
  const rawBasename = extractBasenameFromRouter(routerSource);
  const basename = rawBasename ? ("/" + rawBasename.replace(/^\/+|\/+$/g, "")).replace(/^\/$/, "") : void 0;
  let result;
  if (extraction.kind === "inline") {
    result = buildCombinedRouteMapWithSearch(
      routerFilePath,
      void 0,
      void 0,
      void 0,
      extraction.block
    );
  } else {
    const imported = resolveImportedVariable(routerSource, extraction.name);
    if (imported) {
      const targetFile = resolveImportPath(imported.specifier, routerFilePath);
      if (!targetFile) {
        return { routes: {}, searchSchemas: {} };
      }
      result = buildCombinedRouteMapWithSearch(
        targetFile,
        imported.exportedName
      );
    } else {
      result = buildCombinedRouteMapWithSearch(routerFilePath, extraction.name);
    }
  }
  if (basename) {
    result = applyBasenameToRoutes(result, basename);
  }
  return result;
}
function detectUnresolvableIncludes(routerFilePath) {
  const realPath = resolve2(routerFilePath);
  let source;
  try {
    source = readFileSync3(realPath, "utf-8");
  } catch {
    return [];
  }
  const extraction = extractUrlsFromRouter(source);
  if (!extraction) return [];
  const diagnostics = [];
  if (extraction.kind === "inline") {
    buildCombinedRouteMapWithSearch(
      realPath,
      void 0,
      /* @__PURE__ */ new Set(),
      diagnostics,
      extraction.block
    );
    return diagnostics;
  }
  const imported = resolveImportedVariable(source, extraction.name);
  let targetFile;
  let exportedName;
  if (imported) {
    const resolved = resolveImportPath(imported.specifier, realPath);
    if (!resolved) {
      return [
        {
          pathPrefix: "/",
          namePrefix: null,
          reason: "file-not-found",
          sourceFile: realPath,
          detail: `import "${imported.specifier}" resolved to no file`
        }
      ];
    }
    targetFile = resolved;
    exportedName = imported.exportedName;
  } else {
    targetFile = realPath;
    exportedName = extraction.name;
  }
  buildCombinedRouteMapWithSearch(
    targetFile,
    exportedName,
    /* @__PURE__ */ new Set(),
    diagnostics
  );
  return diagnostics;
}
function detectUnresolvableIncludesForUrlsFile(filePath) {
  const realPath = resolve2(filePath);
  let source;
  try {
    source = readFileSync3(realPath, "utf-8");
  } catch {
    return [];
  }
  const varNames = findUrlsVariableNames(source);
  if (varNames.length === 0) return [];
  const diagnostics = [];
  for (const varName of varNames) {
    buildCombinedRouteMapWithSearch(realPath, varName, /* @__PURE__ */ new Set(), diagnostics);
  }
  return diagnostics;
}
function findRouterFiles(root, filter) {
  const result = [];
  findRouterFilesRecursive(root, filter, result);
  return result;
}
function writeCombinedRouteTypes(root, knownRouterFiles, opts) {
  try {
    const oldCombinedPath = join2(root, "src", "named-routes.gen.ts");
    if (existsSync3(oldCombinedPath)) {
      unlinkSync(oldCombinedPath);
      console.log(
        `[rango] Removed stale combined route types: ${oldCombinedPath}`
      );
    }
  } catch {
  }
  const routerFilePaths = knownRouterFiles ?? findRouterFiles(root);
  if (routerFilePaths.length === 0) return;
  const nestedRouterConflict = findNestedRouterConflict(routerFilePaths);
  if (nestedRouterConflict) {
    throw new Error(formatNestedRouterConflictError(nestedRouterConflict));
  }
  for (const routerFilePath of routerFilePaths) {
    const result = buildCombinedRouteMapForRouterFile(routerFilePath);
    if (Object.keys(result.routes).length === 0 && Object.keys(result.searchSchemas).length === 0) {
      let routerSource;
      try {
        routerSource = readFileSync3(routerFilePath, "utf-8");
      } catch {
        continue;
      }
      if (!extractUrlsFromRouter(routerSource)) continue;
    }
    const outPath = genFileTsPath(routerFilePath);
    const existing = existsSync3(outPath) ? readFileSync3(outPath, "utf-8") : null;
    if (Object.keys(result.routes).length === 0) {
      if (!existing) {
        const emptySource = generateRouteTypesSource({});
        opts?.onWrite?.(outPath, emptySource);
        writeFileSync2(outPath, emptySource);
      }
      continue;
    }
    const hasSearchSchemas = Object.keys(result.searchSchemas).length > 0;
    const source = generateRouteTypesSource(
      result.routes,
      hasSearchSchemas ? result.searchSchemas : void 0
    );
    if (existing !== source) {
      if (opts?.preserveIfLarger && existing) {
        const existingCount = countPublicRouteEntries(existing);
        const newCount = Object.keys(result.routes).filter(
          (name) => !isAutoGeneratedRouteName(name)
        ).length;
        if (existingCount > newCount) {
          continue;
        }
      }
      opts?.onWrite?.(outPath, source);
      writeFileSync2(outPath, source);
      console.log(
        `[rango] Generated route types (${Object.keys(result.routes).length} routes) -> ${outPath}`
      );
    }
  }
}
var ROUTER_CALL_PATTERN, ROUTER_CALL_PATTERN_G;
var init_router_processing = __esm({
  "src/build/route-types/router-processing.ts"() {
    "use strict";
    init_codegen();
    init_source_scan();
    init_include_resolution();
    init_per_module_writer();
    init_route_name();
    ROUTER_CALL_PATTERN = /\bcreateRouter\s*[<(]/;
    ROUTER_CALL_PATTERN_G = /\bcreateRouter\s*[<(]/g;
  }
});

// src/build/generate-route-types.ts
var init_generate_route_types = __esm({
  "src/build/generate-route-types.ts"() {
    "use strict";
    init_param_extraction();
    init_ast_route_extraction();
    init_codegen();
    init_scan_filter();
    init_per_module_writer();
    init_include_resolution();
    init_router_processing();
    init_per_module_writer();
  }
});

// src/vite/plugins/virtual-entries.ts
function getVirtualVersionContent(version) {
  return `export const VERSION = ${JSON.stringify(version)};`;
}
var VIRTUAL_ENTRY_BROWSER, VIRTUAL_ENTRY_SSR, VIRTUAL_IDS;
var init_virtual_entries = __esm({
  "src/vite/plugins/virtual-entries.ts"() {
    "use strict";
    VIRTUAL_ENTRY_BROWSER = `
import {
  createFromReadableStream,
  createFromFetch,
  setServerCallback,
  encodeReply,
  createTemporaryReferenceSet,
} from "@rangojs/router/internal/deps/browser";
import { createElement, StrictMode } from "react";
import { hydrateRoot } from "react-dom/client";
import { rscStream } from "@rangojs/router/internal/deps/html-stream-client";
import { initBrowserApp, Rango } from "@rangojs/router/browser";

async function initializeApp() {
  const deps = {
    createFromFetch,
    createFromReadableStream,
    encodeReply,
    setServerCallback,
    createTemporaryReferenceSet,
  };

  await initBrowserApp({ rscStream, deps });

  hydrateRoot(
    document,
    createElement(StrictMode, null, createElement(Rango))
  );
}

initializeApp().catch(console.error);
`.trim();
    VIRTUAL_ENTRY_SSR = `
import { createFromReadableStream } from "@rangojs/router/internal/deps/ssr";
import { renderToReadableStream } from "react-dom/server.edge";
import { injectRSCPayload } from "@rangojs/router/internal/deps/html-stream-server";
import { createSSRHandler } from "@rangojs/router/ssr";

export const renderHTML = createSSRHandler({
  createFromReadableStream,
  renderToReadableStream,
  injectRSCPayload,
  loadBootstrapScriptContent: () =>
    import.meta.viteRsc.loadBootstrapScriptContent("index"),
});
`.trim();
    VIRTUAL_IDS = {
      browser: "virtual:rsc-router/entry.browser.js",
      ssr: "virtual:rsc-router/entry.ssr.js",
      rsc: "virtual:rsc-router/entry.rsc.js",
      version: "@rangojs/router:version"
    };
  }
});

// src/vite/plugins/version-plugin.ts
var version_plugin_exports = {};
__export(version_plugin_exports, {
  createVersionPlugin: () => createVersionPlugin,
  isViteDepCachePath: () => isViteDepCachePath
});
import { parseAst } from "vite";
function isCodeModule(id) {
  return /\.(tsx?|jsx?)($|\?)/.test(id);
}
function normalizeModuleId(id) {
  return id.split("?", 1)[0];
}
function getClientModuleSignature(source) {
  let program;
  try {
    program = parseAst(source, { lang: "tsx" });
  } catch {
    return void 0;
  }
  let isUseClient = false;
  for (const node of program.body ?? []) {
    if (node?.type === "ExpressionStatement" && node.expression?.type === "Literal" && typeof node.expression.value === "string") {
      if (node.expression.value === "use client") {
        isUseClient = true;
      }
      continue;
    }
    break;
  }
  if (!isUseClient) return void 0;
  const exports = /* @__PURE__ */ new Set();
  let hasDefault = false;
  let hasExportAll = false;
  const collectBindingNames = (pattern) => {
    if (!pattern) return;
    if (pattern.type === "Identifier") {
      exports.add(pattern.name);
    } else if (pattern.type === "ObjectPattern") {
      for (const prop of pattern.properties ?? []) {
        if (prop?.type === "RestElement") {
          collectBindingNames(prop.argument);
        } else {
          collectBindingNames(prop?.value);
        }
      }
    } else if (pattern.type === "ArrayPattern") {
      for (const el of pattern.elements ?? []) {
        if (el?.type === "RestElement") {
          collectBindingNames(el.argument);
        } else {
          collectBindingNames(el);
        }
      }
    }
  };
  const collectDeclarationNames = (declaration) => {
    if (!declaration) return;
    if (declaration.type === "VariableDeclaration") {
      for (const decl of declaration.declarations ?? []) {
        collectBindingNames(decl?.id);
      }
      return;
    }
    collectBindingNames(declaration.id);
  };
  for (const node of program.body ?? []) {
    if (node?.type === "ExportDefaultDeclaration") {
      hasDefault = true;
      continue;
    }
    if (node?.type === "ExportAllDeclaration") {
      hasExportAll = true;
      continue;
    }
    if (node?.type !== "ExportNamedDeclaration") continue;
    collectDeclarationNames(node.declaration);
    for (const specifier of node.specifiers ?? []) {
      const exportedName = specifier?.exported?.name ?? specifier?.exported?.value;
      if (exportedName === "default") {
        hasDefault = true;
      } else if (typeof exportedName === "string") {
        exports.add(exportedName);
      }
    }
  }
  return {
    key: JSON.stringify({
      default: hasDefault,
      exportAll: hasExportAll,
      exports: [...exports].sort()
    })
  };
}
function createVersionPlugin() {
  const buildVersion = Date.now().toString(16);
  let currentVersion = buildVersion;
  let isDev = false;
  let server = null;
  let resolvedCacheDir;
  const clientModuleSignatures = /* @__PURE__ */ new Map();
  let versionCounter = 0;
  const bumpVersion = (reason) => {
    currentVersion = Date.now().toString(16) + String(++versionCounter);
    console.log(`[rango] ${reason}, version updated: ${currentVersion}`);
    const rscEnv = server?.environments?.rsc;
    const versionMod = rscEnv?.moduleGraph?.getModuleById(
      "\0" + VIRTUAL_IDS.version
    );
    if (versionMod) {
      rscEnv.moduleGraph.invalidateModule(versionMod);
    }
  };
  return {
    name: "@rangojs/router:version",
    enforce: "pre",
    configResolved(config) {
      isDev = config.command === "serve";
      resolvedCacheDir = config.cacheDir ? String(config.cacheDir).replace(/\\/g, "/") : void 0;
    },
    configureServer(devServer) {
      server = devServer;
      devServer.watcher.on("unlink", (filePath) => {
        if (!isDev) return;
        if (!clientModuleSignatures.has(filePath)) return;
        clientModuleSignatures.delete(filePath);
        bumpVersion("Client module removed");
      });
    },
    resolveId(id) {
      if (id === VIRTUAL_IDS.version) {
        return "\0" + id;
      }
      return null;
    },
    load(id) {
      if (id === "\0" + VIRTUAL_IDS.version) {
        return getVirtualVersionContent(currentVersion);
      }
      return null;
    },
    transform(code, id) {
      if (!isDev || !isCodeModule(id)) return null;
      const normalizedId = normalizeModuleId(id);
      if (!code.includes("use client") && !clientModuleSignatures.has(normalizedId)) {
        return null;
      }
      const signature = getClientModuleSignature(code);
      if (signature) {
        clientModuleSignatures.set(normalizedId, signature);
      } else {
        clientModuleSignatures.delete(normalizedId);
      }
      return null;
    },
    // Track RSC module changes and update version
    async hotUpdate(ctx) {
      if (!isDev) return;
      const isRscModule = this.environment?.name === "rsc";
      if (!isRscModule) return;
      if (isViteDepCachePath(ctx.file, resolvedCacheDir)) return;
      if (ctx.modules.length === 1 && ctx.modules[0].id === "\0" + VIRTUAL_IDS.version) {
        return;
      }
      if (isCodeModule(ctx.file)) {
        const filePath = normalizeModuleId(ctx.file);
        const previousSignature = clientModuleSignatures.get(filePath);
        try {
          const source = await ctx.read();
          const nextSignature = getClientModuleSignature(source);
          if (nextSignature) {
            clientModuleSignatures.set(filePath, nextSignature);
            if (previousSignature && previousSignature.key === nextSignature.key) {
              return;
            }
          } else {
            clientModuleSignatures.delete(filePath);
            if (!previousSignature) {
              if (ctx.modules.length === 0) return;
            }
          }
        } catch {
        }
      } else {
        if (ctx.modules.length === 0) return;
      }
      bumpVersion("RSC module changed");
    }
  };
}
function isViteDepCachePath(filePath, cacheDir) {
  if (!filePath) return false;
  const normalized = filePath.replace(/\\/g, "/");
  if (cacheDir) {
    const normalizedCacheDir = cacheDir.replace(/\\/g, "/").replace(/\/+$/, "");
    if (normalized === normalizedCacheDir || normalized.startsWith(normalizedCacheDir + "/")) {
      return true;
    }
  }
  return /\/node_modules\/\.vite[^/]*\//.test(normalized) || normalized.includes("/.vite-isolated/");
}
var init_version_plugin = __esm({
  "src/vite/plugins/version-plugin.ts"() {
    "use strict";
    init_virtual_entries();
  }
});

// src/vite/plugins/virtual-stub-plugin.ts
var virtual_stub_plugin_exports = {};
__export(virtual_stub_plugin_exports, {
  createVirtualStubPlugin: () => createVirtualStubPlugin
});
function createVirtualStubPlugin() {
  const STUB_PREFIXES = [
    "virtual:rsc-router/",
    "virtual:entry-",
    "virtual:vite-rsc/"
  ];
  return {
    name: "@rangojs/router:virtual-stubs",
    resolveId(id) {
      if (STUB_PREFIXES.some((p) => id.startsWith(p))) {
        return "\0stub:" + id;
      }
      return null;
    },
    load(id) {
      if (id.startsWith("\0stub:")) {
        return "export default {}";
      }
      return null;
    }
  };
}
var init_virtual_stub_plugin = __esm({
  "src/vite/plugins/virtual-stub-plugin.ts"() {
    "use strict";
  }
});

// src/build/runtime-discovery.ts
var runtime_discovery_exports = {};
__export(runtime_discovery_exports, {
  discoverAndWriteRouteTypes: () => discoverAndWriteRouteTypes
});
import { resolve as resolve3 } from "node:path";
import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
async function discoverAndWriteRouteTypes(opts) {
  let createViteServer;
  let loadConfigFromFile;
  let rsc;
  try {
    const vite = await import("vite");
    createViteServer = vite.createServer;
    loadConfigFromFile = vite.loadConfigFromFile;
  } catch {
    throw new Error(
      "Runtime discovery requires 'vite'. Install it with: pnpm add -D vite"
    );
  }
  try {
    const rscMod = await import("@vitejs/plugin-rsc");
    rsc = rscMod.default;
  } catch {
    throw new Error(
      "Runtime discovery requires '@vitejs/plugin-rsc'. Install it with: pnpm add -D @vitejs/plugin-rsc"
    );
  }
  const { createVersionPlugin: createVersionPlugin2 } = await Promise.resolve().then(() => (init_version_plugin(), version_plugin_exports));
  const { createVirtualStubPlugin: createVirtualStubPlugin2 } = await Promise.resolve().then(() => (init_virtual_stub_plugin(), virtual_stub_plugin_exports));
  let userResolveAlias = opts.resolveAlias;
  if (!userResolveAlias) {
    const configPath = opts.configFile;
    try {
      const loaded = await loadConfigFromFile(
        { command: "serve", mode: "development" },
        configPath,
        opts.root
      );
      if (loaded?.config?.resolve?.alias) {
        userResolveAlias = loaded.config.resolve.alias;
      }
    } catch {
    }
  }
  const entryPath = resolve3(opts.entry);
  let tempServer = null;
  try {
    tempServer = await createViteServer({
      root: opts.root,
      configFile: false,
      server: { middlewareMode: true },
      appType: "custom",
      logLevel: "silent",
      cacheDir: "node_modules/.vite_rango_generate",
      resolve: userResolveAlias ? { alias: userResolveAlias } : void 0,
      esbuild: { jsx: "automatic", jsxImportSource: "react" },
      plugins: [
        rsc({
          entries: {
            client: "virtual:entry-client",
            ssr: "virtual:entry-ssr",
            rsc: entryPath
          }
        }),
        createVersionPlugin2(),
        createVirtualStubPlugin2()
      ]
    });
    const rscEnv = tempServer.environments?.rsc;
    if (!rscEnv?.runner) {
      throw new Error("RSC environment runner not available");
    }
    await rscEnv.runner.import(entryPath);
    const serverMod = await rscEnv.runner.import("@rangojs/router/server");
    const registry = serverMod.RouterRegistry;
    if (!registry || registry.size === 0) {
      throw new Error(
        `No routers found in registry after importing ${opts.entry}`
      );
    }
    const buildMod = await rscEnv.runner.import("@rangojs/router/build");
    const generateManifest = buildMod.generateManifest;
    if (!generateManifest) {
      throw new Error("generateManifest not found in @rangojs/router/build");
    }
    const outputFiles = [];
    let totalRouteCount = 0;
    let routerMountIndex = 0;
    for (const [id, router] of registry) {
      if (!router.urlpatterns) continue;
      const manifest = generateManifest(router.urlpatterns, routerMountIndex);
      routerMountIndex++;
      const rawManifest = manifest.routeManifest;
      const routeManifest = {};
      for (const [name, pattern] of Object.entries(rawManifest)) {
        if (!isAutoGeneratedRouteName(name)) {
          routeManifest[name] = pattern;
        }
      }
      let routeSearchSchemas = manifest.routeSearchSchemas;
      const sourceFile = router.__sourceFile;
      if (!sourceFile) {
        console.warn(
          `[rango] Router "${id}" has no __sourceFile, skipping gen file`
        );
        continue;
      }
      if (sourceFile.includes("node_modules")) {
        throw new Error(
          `[rango] Router "${id}" has sourceFile inside node_modules: ${sourceFile}
This means createRouter() stack trace parsing matched an internal frame.
Set an explicit \`id\` on createRouter() or check the call site.`
        );
      }
      routeSearchSchemas = resolveSearchSchemas(
        Object.keys(routeManifest),
        routeSearchSchemas,
        sourceFile
      );
      const outPath = genFileTsPath(sourceFile);
      const source = generateRouteTypesSource(
        routeManifest,
        routeSearchSchemas && Object.keys(routeSearchSchemas).length > 0 ? routeSearchSchemas : void 0
      );
      const existing = existsSync4(outPath) ? readFileSync4(outPath, "utf-8") : null;
      if (existing !== source) {
        writeFileSync3(outPath, source);
      }
      const routeCount = Object.keys(routeManifest).length;
      totalRouteCount += routeCount;
      outputFiles.push(outPath);
      console.log(
        `[rango] Generated route types (${routeCount} routes) -> ${outPath}`
      );
    }
    return {
      routerCount: routerMountIndex,
      routeCount: totalRouteCount,
      outputFiles
    };
  } finally {
    if (tempServer) {
      await tempServer.close();
    }
  }
}
var init_runtime_discovery = __esm({
  "src/build/runtime-discovery.ts"() {
    "use strict";
    init_generate_route_types();
    init_route_name();
  }
});

// src/bin/rango.ts
init_generate_route_types();
import { resolve as resolve4, dirname as dirname3 } from "node:path";
import { readFileSync as readFileSync5, statSync, existsSync as existsSync5 } from "node:fs";
var [command, ...rawArgs] = process.argv.slice(2);
if (command === "generate") {
  let mode = "default";
  let configFile;
  const positionalArgs = [];
  for (let i = 0; i < rawArgs.length; i++) {
    const arg = rawArgs[i];
    if (arg === "--runtime") {
      mode = "runtime";
    } else if (arg === "--static") {
      mode = "static";
    } else if (arg === "--config") {
      configFile = rawArgs[++i];
      if (!configFile) {
        console.error("[rango] --config requires a path argument");
        process.exit(1);
      }
    } else if (arg.startsWith("--")) {
      console.error(`[rango] Unknown flag: ${arg}`);
      process.exit(1);
    } else {
      positionalArgs.push(arg);
    }
  }
  if (positionalArgs.length === 0) {
    console.error(
      "[rango] Usage: rango generate <file|dir> [file2 ...] [--runtime|--static] [--config <path>]"
    );
    process.exit(1);
  }
  if (configFile && mode !== "runtime") {
    console.warn("[rango] --config is only used with --runtime, ignoring");
  }
  if (mode === "runtime") {
    runRuntimeDiscovery(positionalArgs, configFile).catch((err) => {
      console.error(`[rango] Runtime discovery failed: ${err.message}`);
      process.exit(1);
    });
  } else {
    runStaticGeneration(positionalArgs, mode);
  }
} else {
  if (command && command !== "help" && command !== "--help" && command !== "-h") {
    console.error(`[rango] Unknown command: ${command}
`);
  }
  console.log(`Usage: rango generate <file|dir> [file2 ...] [--runtime|--static] [--config <path>]

  Auto-detects file type (createRouter, urls) and generates
  the appropriate .gen.ts route type files.

Modes:
  (default)   Static parser with error on unresolvable includes
  --runtime   Vite-based runtime discovery (100% coverage)
              Requires vite and @vitejs/plugin-rsc
  --static    Static parser, accept partial output with warnings

Options:
  --config <path>  Path to vite.config.ts (--runtime only, auto-detected if omitted)

Examples:
  rango generate src/router.tsx
  rango generate src/router.tsx --runtime
  rango generate src/ --static`);
  process.exit(
    command && command !== "help" && command !== "--help" && command !== "-h" ? 1 : 0
  );
}
function findProjectRoot(fromPath) {
  let dir = dirname3(resolve4(fromPath));
  while (dir !== dirname3(dir)) {
    if (existsSync5(resolve4(dir, "package.json")) || existsSync5(resolve4(dir, "vite.config.ts")) || existsSync5(resolve4(dir, "vite.config.js"))) {
      return dir;
    }
    dir = dirname3(dir);
  }
  return process.cwd();
}
function runStaticGeneration(args, mode) {
  const files = [];
  for (const arg of args) {
    const resolved = resolve4(arg);
    try {
      if (statSync(resolved).isDirectory()) {
        files.push(...findTsFiles(resolved));
      } else {
        files.push(resolved);
      }
    } catch {
      console.warn(`[rango] Skipping ${arg}: not found`);
    }
  }
  if (files.length === 0) {
    console.log("[rango] No files to process");
    process.exit(0);
  }
  const routerFiles = [];
  const urlsFiles = [];
  for (const filePath of files) {
    try {
      const source = readFileSync5(filePath, "utf-8");
      if (/\bcreateRouter\s*[<(]/.test(source)) {
        routerFiles.push(filePath);
      }
      if (source.includes("urls(")) {
        urlsFiles.push(filePath);
      }
    } catch (err) {
      console.warn(
        `[rango] Failed to process ${filePath}: ${err.message}`
      );
    }
  }
  const allDiagnostics = [];
  for (const routerFile of routerFiles) {
    const diagnostics = detectUnresolvableIncludes(routerFile);
    for (const d of diagnostics) {
      allDiagnostics.push({ ...d, routerFile });
    }
  }
  const routerFileSet = new Set(routerFiles);
  for (const urlsFile of urlsFiles) {
    if (routerFileSet.has(urlsFile)) continue;
    const diagnostics = detectUnresolvableIncludesForUrlsFile(urlsFile);
    for (const d of diagnostics) {
      allDiagnostics.push({ ...d, routerFile: urlsFile });
    }
  }
  const seen = /* @__PURE__ */ new Set();
  const uniqueDiagnostics = allDiagnostics.filter((d) => {
    const key = `${d.sourceFile}:${d.pathPrefix}:${d.reason}`;
    if (seen.has(key)) return false;
    seen.add(key);
    return true;
  });
  if (uniqueDiagnostics.length > 0 && mode === "default") {
    console.error("\n[rango] Unresolvable includes detected:\n");
    formatDiagnostics(uniqueDiagnostics);
    console.error(
      "\nThe static parser cannot resolve these includes because they use factory functions or dynamic expressions.\n\nOptions:\n  rango generate <path> --runtime   Use Vite-based discovery (requires vite)\n  rango generate <path> --static    Accept partial output (missing routes above)\n"
    );
    process.exit(1);
  }
  if (uniqueDiagnostics.length > 0 && mode === "static") {
    console.warn(
      "\n[rango] Warning: partial output (unresolvable includes):\n"
    );
    formatDiagnostics(uniqueDiagnostics);
    console.warn("");
  }
  const nestedRouterConflict = findNestedRouterConflict(routerFiles);
  if (nestedRouterConflict) {
    console.error(
      `
${formatNestedRouterConflictError(nestedRouterConflict, "[rango]")}
`
    );
    process.exit(1);
  }
  for (const urlsFile of urlsFiles) {
    writePerModuleRouteTypesForFile(urlsFile);
  }
  for (const routerFile of routerFiles) {
    const projectRoot = findProjectRoot(routerFile);
    writeCombinedRouteTypes(projectRoot, [routerFile]);
  }
  console.log(
    `[rango] Processed ${files.length} file(s)${routerFiles.length ? ` (${routerFiles.length} router)` : ""}`
  );
  process.exit(0);
}
async function runRuntimeDiscovery(args, configFile) {
  const files = [];
  for (const arg of args) {
    const resolved = resolve4(arg);
    try {
      if (statSync(resolved).isDirectory()) {
        files.push(...findTsFiles(resolved));
      } else {
        files.push(resolved);
      }
    } catch {
      console.warn(`[rango] Skipping ${arg}: not found`);
    }
  }
  const routerEntries = [];
  for (const filePath of files) {
    try {
      const source = readFileSync5(filePath, "utf-8");
      if (/\bcreateRouter\s*[<(]/.test(source)) {
        routerEntries.push(filePath);
      }
      if (source.includes("urls(")) {
        writePerModuleRouteTypesForFile(filePath);
      }
    } catch {
    }
  }
  if (routerEntries.length === 0) {
    console.error("[rango] No router files found in the provided paths");
    process.exit(1);
  }
  const nestedRouterConflict = findNestedRouterConflict(routerEntries);
  if (nestedRouterConflict) {
    console.error(
      `
${formatNestedRouterConflictError(nestedRouterConflict, "[rango]")}
`
    );
    process.exit(1);
  }
  let discoverAndWriteRouteTypes2;
  try {
    const mod = await Promise.resolve().then(() => (init_runtime_discovery(), runtime_discovery_exports));
    discoverAndWriteRouteTypes2 = mod.discoverAndWriteRouteTypes;
  } catch (err) {
    if (err.code === "ERR_MODULE_NOT_FOUND" || err.code === "MODULE_NOT_FOUND") {
      console.error(
        "[rango] Runtime discovery requires 'vite' and '@vitejs/plugin-rsc'.\nInstall them with: pnpm add -D vite @vitejs/plugin-rsc"
      );
    } else {
      console.error(`[rango] Failed to load runtime discovery: ${err.message}`);
    }
    process.exit(1);
  }
  for (const entry of routerEntries) {
    const projectRoot = findProjectRoot(entry);
    const result = await discoverAndWriteRouteTypes2({
      root: projectRoot,
      configFile,
      entry
    });
    console.log(
      `[rango] Runtime discovery: ${result.routerCount} router(s), ${result.routeCount} route(s)`
    );
  }
}
function formatDiagnostics(diagnostics) {
  for (const d of diagnostics) {
    const prefix = d.namePrefix ? `${d.namePrefix}.*` : `${d.pathPrefix}*`;
    console.error(`  ${prefix}`);
    console.error(`    Reason:  ${d.reason} -- ${d.detail}`);
    console.error(`    Source:  ${d.sourceFile}`);
  }
}
