{"version":3,"sources":["../../src/bin/generate-page-routes.ts","../../src/route-parser.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from 'fs';\nimport path from 'path';\nimport { parseRoutesFromFile } from '../route-parser';\n\nconst args = process.argv.slice(2);\n\nfunction getArg(name: string, defaultValue: string): string {\n  const index = args.indexOf(name);\n  if (index !== -1 && args[index + 1]) {\n    return args[index + 1];\n  }\n  return defaultValue;\n}\n\nconst appPath = getArg('--app-path', './client/src/app.tsx');\nconst outDir = path.resolve(process.cwd(), getArg('--out-dir', './dist'));\nconst filename = getArg('--filename', 'page-routes.json');\n\ntry {\n  // page-routes 不带 basePath 前缀（basePath 为空），供日志服务消费\n  const routes = parseRoutesFromFile(appPath, '');\n  if (!fs.existsSync(outDir)) {\n    fs.mkdirSync(outDir, { recursive: true });\n  }\n  const outPath = path.resolve(outDir, filename);\n  fs.writeFileSync(outPath, JSON.stringify(routes, null, 2));\n  console.log(`[page-routes] Generated ${outPath} (${routes.length} routes)`);\n} catch (error) {\n  console.warn('[page-routes] Failed to generate page-routes.json, writing empty fallback:', error);\n  if (!fs.existsSync(outDir)) {\n    fs.mkdirSync(outDir, { recursive: true });\n  }\n  fs.writeFileSync(path.resolve(outDir, filename), JSON.stringify([], null, 2));\n}\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport * as crypto from 'crypto';\nimport { parse } from '@babel/parser';\nimport _traverse from '@babel/traverse';\nimport * as t from '@babel/types';\n\n// Handle CJS default export interop in ESM context\nconst traverse = typeof _traverse === 'function' ? _traverse : (_traverse as any).default;\n\nexport interface PageRouteInfo {\n  path?: string;\n  index?: boolean;\n  [key: string]: unknown;\n}\n\nexport interface ParseRoutesOptions {\n  /** If true, prefix all routes with basePath. Default: true */\n  applyBasePath?: boolean;\n}\n\nexport function routeParserLog(\n  level: 'log' | 'warn' | 'error' | 'info',\n  message: string,\n  ...args: unknown[]\n): void {\n  const prefix = '[route-parser]';\n  const logMessage = `${prefix} ${message}`;\n  switch (level) {\n    case 'warn':\n      console.warn(logMessage, ...args);\n      break;\n    case 'error':\n      console.error(logMessage, ...args);\n      break;\n    case 'info':\n      console.info(logMessage, ...args);\n      break;\n    default:\n      console.log(logMessage, ...args);\n  }\n}\n\nexport function calculateFileHash(filePath: string): string | null {\n  try {\n    const content = fs.readFileSync(filePath, 'utf-8');\n    return crypto.createHash('md5').update(content).digest('hex');\n  } catch (error) {\n    routeParserLog('warn', 'Failed to calculate file hash:', (error as Error).message);\n    return null;\n  }\n}\n\nexport function isRouteComponent(openingElement: t.JSXOpeningElement): boolean {\n  return (\n    t.isJSXIdentifier(openingElement.name) &&\n    openingElement.name.name === 'Route'\n  );\n}\n\nexport function evaluateTemplateLiteral(templateLiteral: t.TemplateLiteral): string {\n  const quasis = templateLiteral.quasis;\n  const expressions = templateLiteral.expressions;\n\n  if (quasis.length === 1 && expressions.length === 0) {\n    return quasis[0].value.raw;\n  }\n\n  return quasis.map((q) => q.value.raw).join('');\n}\n\nexport function extractPageRouteInfo(openingElement: t.JSXOpeningElement): PageRouteInfo {\n  const routeInfo: PageRouteInfo = {};\n\n  openingElement.attributes.forEach((attr) => {\n    if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {\n      const name = attr.name.name;\n      let value: unknown;\n\n      if (attr.value) {\n        if (t.isStringLiteral(attr.value)) {\n          value = attr.value.value;\n        } else if (t.isJSXExpressionContainer(attr.value)) {\n          const expression = attr.value.expression;\n          if (t.isStringLiteral(expression)) {\n            value = expression.value;\n          } else if (t.isTemplateLiteral(expression)) {\n            value = evaluateTemplateLiteral(expression);\n          } else {\n            value = true;\n          }\n        }\n      } else {\n        value = true;\n      }\n\n      routeInfo[name] = value;\n    }\n  });\n\n  return routeInfo;\n}\n\nexport function buildFullPath(\n  routeStack: PageRouteInfo[],\n  currentRoute: PageRouteInfo\n): string | null {\n  let fullPath = '';\n\n  for (let i = 0; i < routeStack.length; i++) {\n    if (routeStack[i].path) {\n      let parentPath = routeStack[i].path!;\n      if (!parentPath.startsWith('/')) parentPath = `/${parentPath}`;\n      if (parentPath.endsWith('/') && parentPath !== '/') {\n        parentPath = parentPath.slice(0, -1);\n      }\n\n      fullPath += parentPath === '/' ? '' : parentPath;\n    }\n  }\n\n  if (currentRoute.index) {\n    return fullPath || '/';\n  } else if (currentRoute.path) {\n    const routePath = currentRoute.path;\n\n    if (routePath === '*') {\n      return null;\n    }\n\n    if (!routePath.startsWith('/')) {\n      fullPath = `${fullPath}/${routePath}`;\n    } else {\n      fullPath = routePath;\n    }\n\n    if (fullPath === '') fullPath = '/';\n    if (!fullPath.startsWith('/')) fullPath = `/${fullPath}`;\n\n    return fullPath;\n  }\n\n  return null;\n}\n\n/**\n * Parse routes from the app file at build time.\n * @param appPath - Path to app.tsx (relative to cwd or absolute)\n * @param basePath - Normalized base path prefix (e.g., '/my_plugin', or '' for no prefix)\n * @param options - Parse options\n * @returns Array of route definitions\n */\nexport function parseRoutesFromFile(\n  appPath: string,\n  basePath: string,\n  options: ParseRoutesOptions = {}\n): Array<{ path: string }> {\n  const { applyBasePath = true } = options;\n  const defaultPath = applyBasePath && basePath ? `${basePath}/` : '/';\n\n  try {\n    const appFilePath = path.resolve(process.cwd(), appPath);\n\n    if (!fs.existsSync(appFilePath)) {\n      throw new Error(`App file does not exist: ${appFilePath}`);\n    }\n\n    const sourceCode = fs.readFileSync(appFilePath, 'utf-8');\n\n    const ast = parse(sourceCode, {\n      sourceType: 'module',\n      plugins: [\n        'jsx',\n        'typescript',\n        'decorators-legacy',\n        'classProperties',\n        'objectRestSpread',\n        'functionBind',\n        'exportDefaultFrom',\n        'exportNamespaceFrom',\n        'dynamicImport',\n        'nullishCoalescingOperator',\n        'optionalChaining',\n      ],\n    });\n\n    const routeSet = new Set<string>();\n    const routeStack: PageRouteInfo[] = [];\n\n    traverse(ast, {\n      JSXElement: {\n        enter(nodePath: any) {\n          const { openingElement } = nodePath.node;\n          if (isRouteComponent(openingElement)) {\n            routeStack.push(extractPageRouteInfo(openingElement));\n          }\n        },\n        exit(nodePath: any) {\n          const { openingElement } = nodePath.node;\n          if (isRouteComponent(openingElement)) {\n            const currentRoute = routeStack.pop();\n            if (currentRoute && currentRoute.path === '*') return;\n            if (currentRoute && (currentRoute.path || currentRoute.index)) {\n              const fullPath = buildFullPath(routeStack, currentRoute);\n              if (fullPath) routeSet.add(fullPath);\n            }\n          }\n        },\n      },\n    });\n\n    const routes = Array.from(routeSet).map((routePath) => ({\n      path: applyBasePath && basePath ? `${basePath}${routePath}` : routePath,\n    }));\n    return routes.length > 0 ? routes : [{ path: defaultPath }];\n  } catch (error) {\n    routeParserLog('warn', 'Route parsing failed, using default routes:', (error as Error).message);\n    return [{ path: defaultPath }];\n  }\n}\n"],"mappings":"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","names":["traverse","_traverse","default","routeParserLog","level","message","args","prefix","logMessage","console","warn","error","info","log","isRouteComponent","openingElement","isJSXIdentifier","name","evaluateTemplateLiteral","templateLiteral","quasis","expressions","length","value","raw","map","q","join","extractPageRouteInfo","routeInfo","attributes","forEach","attr","isJSXAttribute","isStringLiteral","isJSXExpressionContainer","expression","isTemplateLiteral","buildFullPath","routeStack","currentRoute","fullPath","i","path","parentPath","startsWith","endsWith","slice","index","routePath","parseRoutesFromFile","appPath","basePath","options","applyBasePath","defaultPath","appFilePath","resolve","process","cwd","existsSync","Error","sourceCode","readFileSync","ast","parse","sourceType","plugins","routeSet","Set","traverse","JSXElement","enter","nodePath","node","push","exit","pop","add","routes","Array","from","error","routeParserLog","message","args","process","argv","slice","getArg","name","defaultValue","index","indexOf","appPath","outDir","path","resolve","cwd","filename","routes","parseRoutesFromFile","fs","existsSync","mkdirSync","recursive","outPath","writeFileSync","JSON","stringify","console","log","length","error","warn"]}