{"version":3,"sources":["../../../src/core/utils.ts","../../../src/adapters/react-router/route-scanner.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Schedule a microtask-batched callback. Multiple calls within the same\n * microtask only execute the callback once.\n */\nexport function createBatchScheduler(): (fn: () => void) => void {\n  let scheduled = false\n\n  return (fn: () => void) => {\n    if (scheduled) return\n    scheduled = true\n    queueMicrotask(() => {\n      scheduled = false\n      fn()\n    })\n  }\n}\n\n/**\n * Convert a path segment to a readable label.\n * Handles kebab-case, snake_case, camelCase, PascalCase.\n *\n * Examples:\n *  \"user-settings\" -> \"User Settings\"\n *  \"phone_numbers\" -> \"Phone Numbers\"\n *  \"phoneNumbers\"  -> \"Phone Numbers\"\n *  \"BillingOverview\" -> \"Billing Overview\"\n */\nexport function pathSegmentToLabel(segment: string): string {\n  return (\n    segment\n      // Insert space before uppercase letters in camelCase/PascalCase\n      .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n      // Replace hyphens and underscores with spaces\n      .replace(/[-_]/g, ' ')\n      // Capitalize first letter of each word\n      .replace(/\\b\\w/g, (c) => c.toUpperCase())\n      .trim()\n  )\n}\n\n/**\n * Convert a full path to a readable label.\n * Uses the last meaningful segment.\n *\n * \"/billing/overview\" -> \"Billing Overview\"\n * \"/settings\" -> \"Settings\"\n * \"/\" -> \"Home\"\n */\nexport function pathToLabel(path: string): string {\n  if (path === '/' || path === '') return 'Home'\n\n  const segments = path.split('/').filter(Boolean)\n  // Filter out dynamic segments like :id, [id], etc.\n  const meaningful = segments.filter((s) => !s.startsWith(':') && !s.startsWith('['))\n  const last = meaningful[meaningful.length - 1]\n\n  return last ? pathSegmentToLabel(last) : 'Home'\n}\n\n/**\n * Convert a full path to a group name.\n * Uses the first meaningful segment.\n *\n * \"/billing/overview\" -> \"Billing\"\n * \"/settings/team\" -> \"Settings\"\n */\nexport function pathToGroup(path: string): string | undefined {\n  const segments = path.split('/').filter(Boolean)\n  const first = segments[0]\n\n  if (!first || segments.length <= 1) return undefined\n  return pathSegmentToLabel(first)\n}\n\n/**\n * Generate a stable ID from a route path.\n * \"/billing/overview\" -> \"billing-overview\"\n */\nexport function pathToId(path: string): string {\n  return path\n    .replace(/^\\//, '')\n    .replace(/\\/$/, '')\n    .replace(/\\//g, '--')\n    .replace(/[^a-zA-Z0-9-]/g, '')\n    .toLowerCase() || 'home'\n}\n","import type { ReactNode } from 'react'\nimport type { CommandItem, RouteCommandMeta } from '../../core/types'\nimport { pathToLabel, pathToGroup, pathToId } from '../../core/utils'\n\n/**\n * A React Router route object shape (compatible with v6 and v7).\n * We only use the fields we need for scanning.\n */\nexport interface RouteObject {\n  path?: string\n  children?: RouteObject[]\n  handle?: {\n    command?: RouteCommandMeta\n    [key: string]: unknown\n  }\n  [key: string]: unknown\n}\n\n/** An exclude pattern — exact string, glob with *, or RegExp */\ntype ExcludePattern = string | RegExp\n\n/** Paths that are almost never useful as commands */\nconst DEFAULT_EXCLUDE: ExcludePattern[] = [\n  /^\\/(login|logout|signin|signout|signup|register)(\\/|$)/,\n  /^\\/(forgot|reset)-password(\\/|$)/,\n  /^\\/verify-email(\\/|$)/,\n  /^\\/(oauth|auth)\\/callback(\\/|$)/,\n  '/callback',\n  '/404',\n  '/500',\n  '/error',\n  '/not-found',\n  '*',\n]\n\n/** Options for scanRoutes */\nexport interface ScanRoutesOptions {\n  /**\n   * Patterns to exclude from command discovery (merged with defaults).\n   * Supports exact strings, globs with * (e.g. '/admin/*'), and RegExp.\n   */\n  exclude?: ExcludePattern[]\n  /** Set to true to skip the default exclude list */\n  noDefaultExclude?: boolean\n  /** Include routes with dynamic segments like :id or [id] (default: false) */\n  includeDynamic?: boolean\n}\n\n/** Check if a path matches an exclude pattern */\nfunction matchesExclude(path: string, pattern: ExcludePattern): boolean {\n  if (pattern instanceof RegExp) {\n    return pattern.test(path)\n  }\n  // Exact match for standalone '*' (React Router catch-all segment)\n  if (pattern === '*') {\n    return path === '*'\n  }\n  // Glob: '/admin/*' matches '/admin/anything' and '/admin/deep/nested'\n  if (pattern.includes('*')) {\n    const prefix = pattern.replace(/\\/?\\*.*$/, '')\n    return path === prefix || path.startsWith(prefix + '/')\n  }\n  // Exact match\n  return path === pattern\n}\n\n/**\n * Scan a React Router route tree and extract command items.\n *\n * Walks the route tree recursively. For each route with a path,\n * creates a CommandItem. If the route has `handle.command` metadata,\n * uses it to enrich the item.\n *\n * @param routes - React Router route objects\n * @param options - Scan options (exclude paths, etc.)\n * @returns Array of discovered command items\n */\nexport function scanRoutes(\n  routes: RouteObject[],\n  options?: ScanRoutesOptions | string,\n): CommandItem[] {\n  // Support legacy signature: scanRoutes(routes, parentPath)\n  const opts: ScanRoutesOptions = typeof options === 'string' ? {} : (options ?? {})\n  const parentPath = typeof options === 'string' ? options : ''\n\n  return scanRoutesInternal(routes, parentPath, opts)\n}\n\nfunction scanRoutesInternal(\n  routes: RouteObject[],\n  parentPath: string,\n  options: ScanRoutesOptions,\n): CommandItem[] {\n  const commands: CommandItem[] = []\n  const excludePatterns: ExcludePattern[] = options.noDefaultExclude\n    ? (options.exclude ?? [])\n    : [...DEFAULT_EXCLUDE, ...(options.exclude ?? [])]\n\n  for (const route of routes) {\n    const fullPath = buildPath(parentPath, route.path)\n\n    // Only create commands for routes with paths (skip layout routes)\n    if (route.path !== undefined && route.path !== '') {\n      // Skip dynamic routes (:id, [id]) unless explicitly included or has handle.command\n      const hasDynamic = /[:[\\*]/.test(fullPath)\n      const hasCommandMeta = !!route.handle?.command\n\n      // Check if path matches any exclude pattern\n      const isExcluded = excludePatterns.some(\n        (p) => matchesExclude(fullPath, p) || matchesExclude(route.path ?? '', p),\n      )\n\n      if (isExcluded) {\n        // Still recurse into children — only this path is excluded\n      } else if (hasDynamic && !options.includeDynamic && !hasCommandMeta) {\n        // Skip dynamic routes — can't navigate to /billing/:uuid without a real ID\n        // Unless the route explicitly declares handle.command (user opted in)\n      } else {\n        const meta = route.handle?.command\n\n        commands.push({\n          id: pathToId(fullPath),\n          label: meta?.label ?? (route.title as string) ?? pathToLabel(fullPath),\n          description: meta?.description,\n          keywords: meta?.keywords,\n          group: meta?.group ?? pathToGroup(fullPath),\n          icon: meta?.icon ?? (route.icon as ReactNode),\n          permissions: meta?.permissions,\n          priority: meta?.priority,\n          hidden: meta?.hidden,\n          href: fullPath,\n        })\n      }\n    }\n\n    // Recurse into children\n    if (route.children) {\n      commands.push(...scanRoutesInternal(route.children, fullPath, options))\n    }\n  }\n\n  return commands\n}\n\n/**\n * Build a full path from parent + child segments.\n */\nfunction buildPath(parent: string, child?: string): string {\n  if (!child) return parent\n  if (child.startsWith('/')) return child\n\n  const base = parent.endsWith('/') ? parent : parent + '/'\n  return base + child\n}\n"]}