{"version":3,"file":"utils.mjs","sources":["../../src/utils.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport * as path from 'node:path';\nimport { promisify } from 'node:util';\nimport {\n  defaultRunDirName,\n  getMidsceneRunSubDir,\n} from '@midscene/shared/common';\nimport {\n  MIDSCENE_CACHE,\n  MIDSCENE_DEBUG_MODE,\n  globalConfigManager,\n} from '@midscene/shared/env';\nimport { getRunningPkgInfo } from '@midscene/shared/node';\nimport { assert, logMsg } from '@midscene/shared/utils';\nimport {\n  escapeScriptTag,\n  ifInBrowser,\n  ifInWorker,\n  uuid,\n} from '@midscene/shared/utils';\nimport type { Cache, Rect, ReportDumpWithAttributes } from './types';\n\nlet logEnvReady = false;\n\nexport { appendFileSync } from 'node:fs';\n\nexport const groupedActionDumpFileExt = 'web-dump.json';\n\nfunction htmlScriptCloseTag(): string {\n  // biome-ignore lint/style/useTemplate: keep this token runtime-built for inline report bundles\n  return String.fromCharCode(60) + '/script>';\n}\n\n/**\n * Process cache configuration with environment variable support and backward compatibility.\n *\n * @param cache - The original cache configuration\n * @param cacheId - The cache ID to use as:\n *   1. Fallback ID when cache is true or cache object has no ID\n *   2. Legacy cacheId when cache is undefined (requires MIDSCENE_CACHE env var)\n * @returns Processed cache configuration\n */\nexport function processCacheConfig(\n  cache: Cache | undefined,\n  cacheId: string,\n): Cache | undefined {\n  // 1. New cache object configuration (highest priority)\n  if (cache !== undefined) {\n    if (cache === false) {\n      return false; // Keep explicit disablement distinguishable from missing config.\n    }\n\n    if (cache === true) {\n      // Auto-generate ID using cacheId for CLI/YAML scenarios\n      // Agent will validate and reject this later if needed\n      return { id: cacheId };\n    }\n\n    // cache is object configuration\n    if (typeof cache === 'object' && cache !== null) {\n      // Auto-generate ID using cacheId when missing (for CLI/YAML scenarios)\n      if (!cache.id) {\n        return { ...cache, id: cacheId };\n      }\n      return cache;\n    }\n  }\n\n  // 2. Backward compatibility: support old cacheId (requires environment variable)\n  // When cache is undefined, check if legacy cacheId mode is enabled via env var\n  const envEnabled = globalConfigManager.getEnvConfigInBoolean(MIDSCENE_CACHE);\n\n  if (envEnabled && cacheId) {\n    return { id: cacheId };\n  }\n\n  // 3. No cache configuration\n  return undefined;\n}\n\nconst reportInitializedMap = new Map<string, boolean>();\nconst reportGroupIdMap = new Map<string, string>();\n\ndeclare const __DEV_REPORT_PATH__: string;\n\nexport function getReportTpl() {\n  if (typeof __DEV_REPORT_PATH__ === 'string' && __DEV_REPORT_PATH__) {\n    return fs.readFileSync(__DEV_REPORT_PATH__, 'utf-8');\n  }\n  const reportTpl = 'REPLACE_ME_WITH_REPORT_HTML';\n\n  return reportTpl;\n}\n\n/**\n * Insert content before </html> in an HTML string.\n * Falls back to simple concatenation if </html> is not found.\n */\nexport function insertContentBeforeClosingHtml(\n  html: string,\n  content: string,\n): string {\n  const htmlEndIdx = html.lastIndexOf('</html>');\n  if (htmlEndIdx === -1) {\n    return html + content;\n  }\n  return `${html.slice(0, htmlEndIdx)}${content}\\n${html.slice(htmlEndIdx)}`;\n}\n\n/**\n * high performance, insert script before </html> in HTML file\n * only truncate and append, no temporary file\n */\nexport function insertScriptBeforeClosingHtml(\n  filePath: string,\n  scriptContent: string,\n): void {\n  const htmlEndTag = '</html>';\n  const stat = fs.statSync(filePath);\n\n  const readSize = Math.min(stat.size, 4096);\n  const start = Math.max(0, stat.size - readSize);\n  const buffer = Buffer.alloc(stat.size - start);\n  const fd = fs.openSync(filePath, 'r');\n  fs.readSync(fd, buffer, 0, buffer.length, start);\n  fs.closeSync(fd);\n\n  const tailStr = buffer.toString('utf8');\n  const htmlEndIdx = tailStr.lastIndexOf(htmlEndTag);\n  if (htmlEndIdx === -1) {\n    throw new Error(`No </html> found in file：${filePath}`);\n  }\n\n  // calculate the correct byte position: char position to byte position\n  const beforeHtmlInTail = tailStr.slice(0, htmlEndIdx);\n  const htmlEndPos = start + Buffer.byteLength(beforeHtmlInTail, 'utf8');\n\n  // truncate to </html> before\n  fs.truncateSync(filePath, htmlEndPos);\n  // append script and </html>\n  fs.appendFileSync(filePath, `${scriptContent}\\n${htmlEndTag}\\n`);\n}\n\nexport function reportHTMLContent(\n  dumpData: string | ReportDumpWithAttributes,\n  reportPath?: string,\n  appendReport?: boolean,\n  withTpl = true, // whether return with report template, default = true\n): string {\n  let tpl = '';\n  if (withTpl) {\n    tpl = getReportTpl();\n\n    if (!tpl) {\n      console.warn('reportTpl is not set, will not write report');\n      return '';\n    }\n  }\n  // if reportPath is set, it means we are in write to file mode\n  const writeToFile = reportPath && !ifInBrowser;\n  let dumpContent = '';\n  const closeTag = htmlScriptCloseTag();\n\n  const resolveAutoGroupId = (): string => {\n    if (!reportPath || !appendReport) {\n      return uuid();\n    }\n\n    const existingGroupId = reportGroupIdMap.get(reportPath);\n    if (existingGroupId) {\n      return existingGroupId;\n    }\n\n    const newGroupId = uuid();\n    reportGroupIdMap.set(reportPath, newGroupId);\n    return newGroupId;\n  };\n\n  if (typeof dumpData === 'string') {\n    const groupId = resolveAutoGroupId();\n    // do not use template string here, will cause bundle error\n    dumpContent =\n      // biome-ignore lint/style/useTemplate: <explanation>\n      '<script type=\"midscene_web_dump\" type=\"application/json\" data-group-id=\"' +\n      encodeURIComponent(groupId) +\n      '\">\\n' +\n      escapeScriptTag(dumpData) +\n      '\\n' +\n      closeTag;\n  } else {\n    const { dumpString, attributes } = dumpData;\n    const attributesArr = Object.entries(attributes || {})\n      .filter((entry): entry is [string, string | number | boolean] => {\n        return entry[1] !== undefined && entry[1] !== null;\n      })\n      .map(([key, value]) => {\n        return `${key}=\"${encodeURIComponent(value)}\"`;\n      });\n\n    dumpContent =\n      // do not use template string here, will cause bundle error\n      // biome-ignore lint/style/useTemplate: <explanation>\n      '<script type=\"midscene_web_dump\" type=\"application/json\" ' +\n      attributesArr.join(' ') +\n      '>\\n' +\n      escapeScriptTag(dumpString) +\n      '\\n' +\n      closeTag;\n  }\n\n  if (writeToFile) {\n    if (!appendReport) {\n      writeFileSync(\n        reportPath!,\n        insertContentBeforeClosingHtml(tpl, dumpContent),\n        { flag: 'w' },\n      );\n      return reportPath!;\n    }\n\n    if (!reportInitializedMap.get(reportPath!)) {\n      writeFileSync(reportPath!, tpl, { flag: 'w' });\n      reportInitializedMap.set(reportPath!, true);\n    }\n\n    insertScriptBeforeClosingHtml(reportPath!, dumpContent);\n    return reportPath!;\n  }\n\n  return insertContentBeforeClosingHtml(tpl, dumpContent);\n}\n\nexport function writeDumpReport(\n  fileName: string,\n  dumpData: string | ReportDumpWithAttributes,\n  appendReport?: boolean,\n): string | null {\n  if (ifInBrowser || ifInWorker) {\n    console.log('will not write report in browser');\n    return null;\n  }\n\n  const reportPath = path.join(\n    getMidsceneRunSubDir('report'),\n    `${fileName}.html`,\n  );\n\n  reportHTMLContent(dumpData, reportPath, appendReport);\n\n  if (process.env.MIDSCENE_DEBUG_LOG_JSON) {\n    const jsonPath = `${reportPath}.json`;\n    let data;\n\n    if (typeof dumpData === 'string') {\n      data = JSON.parse(dumpData) as ReportDumpWithAttributes;\n    } else {\n      data = dumpData;\n    }\n\n    writeFileSync(jsonPath, JSON.stringify(data, null, 2), {\n      flag: appendReport ? 'a' : 'w',\n    });\n\n    logMsg(`Midscene - dump file written: ${jsonPath}`);\n  }\n\n  return reportPath;\n}\n\nexport function writeLogFile(opts: {\n  fileName: string;\n  fileExt: string;\n  fileContent: string | ReportDumpWithAttributes;\n  type: 'dump' | 'cache' | 'report' | 'tmp';\n  generateReport?: boolean;\n  appendReport?: boolean;\n}) {\n  if (ifInBrowser || ifInWorker) {\n    return '/mock/report.html';\n  }\n  const { fileName, fileExt, fileContent, type = 'dump' } = opts;\n  const targetDir = getMidsceneRunSubDir(type);\n  // Ensure directory exists\n  if (!logEnvReady) {\n    assert(targetDir, 'logDir should be set before writing dump file');\n\n    // gitIgnore in the parent directory\n    const gitIgnorePath = path.join(targetDir, '../../.gitignore');\n    const gitPath = path.join(targetDir, '../../.git');\n    let gitIgnoreContent = '';\n\n    if (existsSync(gitPath)) {\n      // if the git path exists, we need to add the log folder to the git ignore file\n      if (existsSync(gitIgnorePath)) {\n        gitIgnoreContent = readFileSync(gitIgnorePath, 'utf-8');\n      }\n\n      // ignore the log folder\n      if (!gitIgnoreContent.includes(`${defaultRunDirName}/`)) {\n        writeFileSync(\n          gitIgnorePath,\n          `${gitIgnoreContent}\\n# Midscene.js dump files\\n${defaultRunDirName}/dump\\n${defaultRunDirName}/report\\n${defaultRunDirName}/tmp\\n${defaultRunDirName}/log\\n`,\n          'utf-8',\n        );\n      }\n    }\n\n    logEnvReady = true;\n  }\n\n  const filePath = path.join(targetDir, `${fileName}.${fileExt}`);\n\n  if (type !== 'dump') {\n    // do not write dump file any more\n    writeFileSync(filePath, JSON.stringify(fileContent));\n  }\n\n  if (opts?.generateReport) {\n    return writeDumpReport(fileName, fileContent, opts.appendReport);\n  }\n\n  return filePath;\n}\n\nexport function getTmpDir(): string | null {\n  try {\n    const runningPkgInfo = getRunningPkgInfo();\n    if (!runningPkgInfo) {\n      return null;\n    }\n    const { name } = runningPkgInfo;\n    const tmpPath = path.join(tmpdir(), name);\n    mkdirSync(tmpPath, { recursive: true });\n    return tmpPath;\n  } catch (e) {\n    return null;\n  }\n}\n\nexport function getTmpFile(fileExtWithoutDot: string): string | null {\n  if (ifInBrowser || ifInWorker) {\n    return null;\n  }\n  const tmpDir = getTmpDir();\n  const filename = `${uuid()}.${fileExtWithoutDot}`;\n  return path.join(tmpDir!, filename);\n}\n\nexport function overlapped(container: Rect, target: Rect) {\n  // container and the target have some part overlapped\n  return (\n    container.left < target.left + target.width &&\n    container.left + container.width > target.left &&\n    container.top < target.top + target.height &&\n    container.top + container.height > target.top\n  );\n}\n\nexport async function sleep(ms: number) {\n  return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function replacerForPageObject(_key: string, value: any) {\n  if (value && value.constructor?.name === 'Page') {\n    return '[Page object]';\n  }\n  if (value && value.constructor?.name === 'Browser') {\n    return '[Browser object]';\n  }\n  // Handle ScreenshotItem serialization\n  if (value && typeof value.toSerializable === 'function') {\n    return value.toSerializable();\n  }\n  return value;\n}\n\nexport function stringifyDumpData(data: any, indents?: number) {\n  return JSON.stringify(data, replacerForPageObject, indents);\n}\n\ndeclare const __VERSION__: string;\n\nexport function getVersion() {\n  return __VERSION__;\n}\n\nfunction debugLog(...message: any[]) {\n  // always read from process.env, and cannot be override by modelConfig, overrideAIConfig, etc.\n  // also avoid circular dependency\n  const debugMode = process.env[MIDSCENE_DEBUG_MODE];\n  if (debugMode) {\n    console.log('[Midscene]', ...message);\n  }\n}\n\nlet gitInfoPromise: Promise<{ repoUrl: string; userEmail: string }> | null =\n  null;\n\nfunction getGitInfoAsync(): Promise<{ repoUrl: string; userEmail: string }> {\n  if (gitInfoPromise) return gitInfoPromise;\n\n  const execFileAsync = promisify(execFile);\n\n  gitInfoPromise = Promise.all([\n    execFileAsync('git', ['config', '--get', 'remote.origin.url']).then(\n      ({ stdout }) => stdout.trim(),\n      () => '',\n    ),\n    execFileAsync('git', ['config', '--get', 'user.email']).then(\n      ({ stdout }) => stdout.trim(),\n      () => '',\n    ),\n  ]).then(([repoUrl, userEmail]) => ({ repoUrl, userEmail }));\n\n  return gitInfoPromise;\n}\n\nlet lastReportedRepoUrl = '';\nexport async function uploadTestInfoToServer({\n  testUrl,\n  serverUrl,\n}: { testUrl: string; serverUrl?: string }) {\n  if (!serverUrl) return;\n\n  const { repoUrl, userEmail } = await getGitInfoAsync();\n\n  // Only upload test info if:\n  // 1. Server URL is configured AND\n  // 2. Either:\n  //    - We have a repo URL that's different from last reported one (to avoid duplicate reports)\n  //    - OR we don't have a repo URL but have a test URL (for non-git environments)\n  if (repoUrl ? repoUrl !== lastReportedRepoUrl : !!testUrl) {\n    debugLog('Uploading test info to server', {\n      serverUrl,\n      repoUrl,\n      testUrl,\n      userEmail,\n    });\n\n    fetch(serverUrl, {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n      },\n      body: JSON.stringify({\n        repo_url: repoUrl,\n        test_url: testUrl,\n        user_email: userEmail,\n      }),\n    })\n      .then((response) => response.json())\n      .then((data) => {\n        debugLog('Successfully uploaded test info to server:', data);\n      })\n      .catch((error) =>\n        debugLog('Failed to upload test info to server:', error),\n      );\n    lastReportedRepoUrl = repoUrl;\n  }\n}\n"],"names":["logEnvReady","groupedActionDumpFileExt","htmlScriptCloseTag","String","processCacheConfig","cache","cacheId","undefined","envEnabled","globalConfigManager","MIDSCENE_CACHE","reportInitializedMap","Map","reportGroupIdMap","getReportTpl","reportTpl","insertContentBeforeClosingHtml","html","content","htmlEndIdx","insertScriptBeforeClosingHtml","filePath","scriptContent","htmlEndTag","stat","fs","readSize","Math","start","buffer","Buffer","fd","tailStr","Error","beforeHtmlInTail","htmlEndPos","reportHTMLContent","dumpData","reportPath","appendReport","withTpl","tpl","console","writeToFile","ifInBrowser","dumpContent","closeTag","resolveAutoGroupId","uuid","existingGroupId","newGroupId","groupId","encodeURIComponent","escapeScriptTag","dumpString","attributes","attributesArr","Object","entry","key","value","writeFileSync","writeDumpReport","fileName","ifInWorker","path","getMidsceneRunSubDir","process","jsonPath","data","JSON","logMsg","writeLogFile","opts","fileExt","fileContent","type","targetDir","assert","gitIgnorePath","gitPath","gitIgnoreContent","existsSync","readFileSync","defaultRunDirName","getTmpDir","runningPkgInfo","getRunningPkgInfo","name","tmpPath","tmpdir","mkdirSync","e","getTmpFile","fileExtWithoutDot","tmpDir","filename","overlapped","container","target","sleep","ms","Promise","resolve","setTimeout","replacerForPageObject","_key","stringifyDumpData","indents","getVersion","__VERSION__","debugLog","message","debugMode","MIDSCENE_DEBUG_MODE","gitInfoPromise","getGitInfoAsync","execFileAsync","promisify","execFile","stdout","repoUrl","userEmail","lastReportedRepoUrl","uploadTestInfoToServer","testUrl","serverUrl","fetch","response","error"],"mappings":"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"}