{"version":3,"file":"automator-inspector.cjs","names":["path","fs"],"sources":["../src/automator-inspector.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport automator = require('miniprogram-automator');\n\nimport type { KeyMapItem, ProjectAnalysis, TemplateNode } from './core';\n\ninterface InspectorOptions {\n  projectPath: string;\n  getAnalysis: () => ProjectAnalysis;\n  intervalMs?: number;\n  cliPath?: string;\n  port?: number;\n  suppressTerminal?: boolean;\n  onSnapshot?: (snapshot: {\n    connected: boolean;\n    status: string;\n    route: string;\n    rows: RuntimeRow[];\n    updatedAt: string;\n    debug?: Record<string, unknown>;\n    rawData?: Record<string, unknown>;\n    templateTree?: TemplateNode | null;\n  }) => void;\n}\n\nexport interface RuntimeRow {\n  source: string;\n  key: string;\n  value: unknown;\n  kind: string;\n  confidence: string;\n  expressionSummary: string;\n  wxmlUsages: string[];\n}\n\nfunction normalizeRoute(route: string): string {\n  const withoutQuery = route.split('?')[0] || route;\n  return withoutQuery.startsWith('/') ? withoutQuery.slice(1) : withoutQuery;\n}\n\ninterface RuntimePageState {\n  route: string;\n  rawRoute: string;\n  pageId: number | string;\n  data: Record<string, unknown>;\n}\n\ninterface AutomatorLaunchOptions {\n  projectPath: string;\n  cliPath?: string;\n  args?: string[];\n  port?: number;\n  timeout: number;\n  trustProject: boolean;\n}\n\nfunction launchOptions(options: InspectorOptions, cliPath?: string, args?: string[]): AutomatorLaunchOptions {\n  return {\n    projectPath: options.projectPath,\n    cliPath,\n    args,\n    ...(options.port ? { port: options.port } : {}),\n    timeout: 45_000,\n    trustProject: true,\n  };\n}\n\nfunction getCliJsFallback(cliPath?: string): { cliPath: string; args: string[] } | null {\n  if (!cliPath || path.basename(cliPath) !== 'cli') return null;\n\n  const macosDir = path.dirname(cliPath);\n  const appRoot = path.resolve(macosDir, '..', '..');\n  const cliJs = path.join(macosDir, 'cli.js');\n  const helperNode = path.join(\n    appRoot,\n    'Contents',\n    'Frameworks',\n    'nwjs Framework.framework',\n    'Helpers',\n    'wechatwebdevtools Helper (Renderer).app',\n    'Contents',\n    'MacOS',\n    'node',\n  );\n\n  if (!fs.existsSync(cliJs) || !fs.existsSync(helperNode)) return null;\n  return { cliPath: helperNode, args: [cliJs] };\n}\n\nasync function launchAutomator(options: InspectorOptions): Promise<any> {\n  try {\n    return await automator.launch(launchOptions(options, options.cliPath));\n  } catch (error) {\n    const message = error instanceof Error ? error.message : String(error);\n    const fallback = getCliJsFallback(options.cliPath);\n    if (!fallback || !message.includes('cliPath')) throw error;\n    return automator.launch(launchOptions(options, fallback.cliPath, fallback.args));\n  }\n}\n\nfunction withTimeout<T>(promise: Promise<T>, timeoutMs: number, label: string): Promise<T> {\n  return new Promise<T>((resolve, reject) => {\n    const timer = setTimeout(() => reject(new Error(`${label} timed out after ${timeoutMs}ms`)), timeoutMs);\n    promise.then(\n      (value) => {\n        clearTimeout(timer);\n        resolve(value);\n      },\n      (error) => {\n        clearTimeout(timer);\n        reject(error);\n      },\n    );\n  });\n}\n\nasync function readRuntimePageState(miniProgram: any): Promise<RuntimePageState | null> {\n  // Use the underlying automator protocol directly instead of cached Page objects.\n  // This tracks refresh/navigation better because App.getCurrentPage returns the latest pageId/path.\n  const current = await miniProgram.send('App.getCurrentPage');\n  if (!current || current.pageId == null) return null;\n\n  const dataResult = await miniProgram.send('Page.getData', { pageId: current.pageId });\n  const rawRoute = String(current.path || '');\n  return {\n    route: normalizeRoute(rawRoute),\n    rawRoute,\n    pageId: current.pageId,\n    data: (dataResult?.data || {}) as Record<string, unknown>,\n  };\n}\n\nfunction printableRows(items: KeyMapItem[], data: Record<string, unknown>): RuntimeRow[] {\n  return items.map((item) => ({\n    source: item.sourceName || item.generatedName || 'unknown',\n    key: item.key,\n    value: data[item.key],\n    kind: item.kind,\n    confidence: item.confidence,\n    expressionSummary: item.expressionSummary,\n    wxmlUsages: item.wxmlUsages.map((usage) => usage.snippet),\n  }));\n}\n\nfunction explainAutomatorFailure(error: unknown): string {\n  const message = error instanceof Error ? error.message : String(error);\n  return [\n    '连接微信开发者工具自动化失败。',\n    message,\n    '',\n    '请检查：',\n    '1. 已安装微信开发者工具。',\n    '2. 微信开发者工具 -> 设置 -> 安全设置 -> 服务端口 已开启。',\n    '3. 该 mp-weixin 编译产物可以被微信开发者工具正常打开。',\n  ].join('\\n');\n}\n\nexport async function startAutomatorInspector(options: InspectorOptions): Promise<() => void> {\n  const miniProgram = await launchAutomator(options);\n\n  let closed = false;\n  let lastText = '';\n  let busy = false;\n  const intervalMs = options.intervalMs || 500;\n\n  async function poll(): Promise<void> {\n    if (closed || busy) return;\n    busy = true;\n    try {\n      const state = await withTimeout(readRuntimePageState(miniProgram), 1500, '读取当前页面数据');\n      if (!state) {\n        options.onSnapshot?.({\n          connected: true,\n          status: '已连接，等待当前页面加载',\n          route: '',\n          rows: [],\n          updatedAt: new Date().toISOString(),\n          debug: { keymapPages: Object.keys(options.getAnalysis().pages) },\n          templateTree: null,\n        });\n        return;\n      }\n      const route = state.route;\n      const analysis = options.getAnalysis();\n      const pageAnalysis = analysis.pages[route];\n      if (!pageAnalysis) {\n        options.onSnapshot?.({\n          connected: true,\n          status: '已连接，但当前页面没有可用映射',\n          route,\n          rows: [],\n          updatedAt: new Date().toISOString(),\n          debug: { pageId: state.pageId, rawRoute: state.rawRoute, keymapPages: Object.keys(analysis.pages) },\n          rawData: state.data,\n          templateTree: null,\n        });\n        const text = `当前页面：${route}\\n未找到当前页面的 key 映射。`;\n        if (!options.suppressTerminal && text !== lastText) {\n          lastText = text;\n          console.clear();\n          console.log(text);\n        }\n        return;\n      }\n\n      const rows = printableRows(pageAnalysis.keys, state.data || {});\n      options.onSnapshot?.({\n        connected: true,\n        status: '已连接',\n        route,\n        rows,\n        updatedAt: new Date().toISOString(),\n        debug: { pageId: state.pageId, rawRoute: state.rawRoute, keymapPages: Object.keys(analysis.pages) },\n        rawData: state.data,\n        templateTree: pageAnalysis.templateTree,\n      });\n      const text = JSON.stringify({ route, rows });\n      if (!options.suppressTerminal && text !== lastText) {\n        lastText = text;\n        console.clear();\n        console.log('已在 Web 面板中展示最新运行时变量值。');\n        console.log('当前页面：', route);\n        console.log('按 Ctrl+C 停止。');\n      }\n    } catch (error) {\n      const text = `读取运行时数据失败：${error instanceof Error ? error.message : String(error)}`;\n      options.onSnapshot?.({\n        connected: false,\n        status: text,\n        route: '',\n        rows: [],\n        updatedAt: new Date().toISOString(),\n        debug: { error: text, keymapPages: Object.keys(options.getAnalysis().pages) },\n        templateTree: null,\n      });\n      if (!options.suppressTerminal && text !== lastText) {\n        lastText = text;\n        console.clear();\n        console.log(text);\n      }\n    } finally {\n      busy = false;\n    }\n  }\n\n  const timer = setInterval(() => void poll(), intervalMs);\n  await poll();\n\n  return () => {\n    closed = true;\n    clearInterval(timer);\n    try {\n      miniProgram.disconnect();\n    } catch (_error) {\n      // Ignore shutdown errors from the DevTools websocket.\n    }\n  };\n}\n\nexport { explainAutomatorFailure };\n"],"mappings":"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"}