qat-cli 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1715,12 +1715,23 @@ function generateHTMLReport(data) {
1715
1715
  // src/runners/vitest-runner.ts
1716
1716
  var import_node_child_process = require("child_process");
1717
1717
  var import_node_path6 = __toESM(require("path"), 1);
1718
+ var import_node_fs6 = __toESM(require("fs"), 1);
1719
+ var import_node_os = __toESM(require("os"), 1);
1720
+ var isVerbose = () => process.env.QAT_VERBOSE === "true";
1721
+ function debug(label, ...args) {
1722
+ if (isVerbose()) {
1723
+ console.log(`\x1B[90m [debug:${label}]\x1B[0m`, ...args);
1724
+ }
1725
+ }
1718
1726
  async function runVitest(options) {
1719
1727
  const startTime = Date.now();
1720
1728
  const args = buildVitestArgs(options);
1729
+ debug("vitest", "\u547D\u4EE4\u53C2\u6570:", args.join(" "));
1721
1730
  try {
1722
1731
  const result = await execVitest(args);
1723
1732
  const endTime = Date.now();
1733
+ debug("vitest", `\u89E3\u6790\u7ED3\u679C: ${result.suites.length} \u4E2A\u5957\u4EF6, ${result.suites.reduce((s, su) => s + su.tests.length, 0)} \u4E2A\u7528\u4F8B`);
1734
+ debug("vitest", "\u89E3\u6790\u65B9\u5F0F:", result.parseMethod);
1724
1735
  return {
1725
1736
  type: options.type,
1726
1737
  status: result.success ? "passed" : "failed",
@@ -1785,12 +1796,11 @@ function buildVitestArgs(options) {
1785
1796
  return args;
1786
1797
  }
1787
1798
  async function execVitest(args) {
1788
- const os = await import("os");
1789
- const fs9 = await import("fs");
1790
- const tmpFile = import_node_path6.default.join(os.tmpdir(), `qat-vitest-result-${Date.now()}.json`);
1799
+ const tmpFile = import_node_path6.default.join(import_node_os.default.tmpdir(), `qat-vitest-result-${Date.now()}.json`);
1791
1800
  const argsWithOutput = [...args, "--outputFile", tmpFile];
1792
1801
  return new Promise((resolve, reject) => {
1793
1802
  const npx = process.platform === "win32" ? "npx.cmd" : "npx";
1803
+ debug("vitest", "\u6267\u884C\u547D\u4EE4:", npx, argsWithOutput.join(" "));
1794
1804
  const child = (0, import_node_child_process.execFile)(npx, argsWithOutput, {
1795
1805
  cwd: process.cwd(),
1796
1806
  env: { ...process.env, FORCE_COLOR: "0", NO_COLOR: "1" },
@@ -1798,85 +1808,113 @@ async function execVitest(args) {
1798
1808
  shell: true
1799
1809
  }, (error, stdout, stderr) => {
1800
1810
  const rawOutput = stdout || stderr || "";
1811
+ const exitCode = error && "code" in error ? error.code : 0;
1812
+ debug("vitest", `\u9000\u51FA\u7801: ${exitCode}`);
1813
+ debug("vitest", `stdout \u957F\u5EA6: ${stdout?.length || 0}, stderr \u957F\u5EA6: ${stderr?.length || 0}`);
1801
1814
  let jsonResult = null;
1802
1815
  try {
1803
- if (fs9.existsSync(tmpFile)) {
1804
- jsonResult = fs9.readFileSync(tmpFile, "utf-8");
1805
- fs9.unlinkSync(tmpFile);
1816
+ if (import_node_fs6.default.existsSync(tmpFile)) {
1817
+ jsonResult = import_node_fs6.default.readFileSync(tmpFile, "utf-8");
1818
+ debug("vitest", `\u4ECE\u4E34\u65F6\u6587\u4EF6\u8BFB\u53D6\u5230 JSON (${jsonResult.length} \u5B57\u7B26)`);
1819
+ debug("vitest", "JSON \u524D 500 \u5B57\u7B26:", jsonResult.substring(0, 500));
1820
+ import_node_fs6.default.unlinkSync(tmpFile);
1821
+ } else {
1822
+ debug("vitest", "\u4E34\u65F6\u6587\u4EF6\u4E0D\u5B58\u5728:", tmpFile);
1806
1823
  }
1807
- } catch {
1824
+ } catch (e) {
1825
+ debug("vitest", "\u4E34\u65F6\u6587\u4EF6\u8BFB\u53D6\u5931\u8D25:", e instanceof Error ? e.message : String(e));
1808
1826
  }
1809
1827
  if (jsonResult) {
1810
1828
  try {
1811
- const parsed = parseVitestJSONResult(jsonResult);
1812
- resolve({ ...parsed, rawOutput });
1829
+ const parsed = parseVitestJSON(jsonResult);
1830
+ debug("vitest", "\u4ECE\u4E34\u65F6\u6587\u4EF6\u89E3\u6790\u6210\u529F:", parsed.suites.length, "\u4E2A\u5957\u4EF6");
1831
+ resolve({ ...parsed, rawOutput, parseMethod: "outputFile-JSON" });
1813
1832
  return;
1814
- } catch {
1833
+ } catch (e) {
1834
+ debug("vitest", "\u4E34\u65F6\u6587\u4EF6 JSON \u89E3\u6790\u5931\u8D25:", e instanceof Error ? e.message : String(e));
1815
1835
  }
1816
1836
  }
1837
+ debug("vitest", "\u5C1D\u8BD5\u4ECE stdout \u63D0\u53D6 JSON...");
1817
1838
  try {
1818
- const parsed = parseVitestJSONOutput(rawOutput);
1819
- resolve({ ...parsed, rawOutput });
1820
- } catch {
1821
- if (rawOutput) {
1822
- resolve({ ...parseVitestTextOutput(rawOutput, !!error), rawOutput });
1823
- } else if (error && error.message.includes("ENOENT")) {
1824
- reject(new Error("\u672A\u627E\u5230 vitest\uFF0C\u8BF7\u786E\u4FDD\u5DF2\u5B89\u88C5: npm install -D vitest"));
1825
- } else {
1826
- resolve({ success: !error, suites: [], rawOutput });
1827
- }
1839
+ const parsed = parseFromStdout(rawOutput);
1840
+ debug("vitest", "\u4ECE stdout \u89E3\u6790\u6210\u529F:", parsed.suites.length, "\u4E2A\u5957\u4EF6");
1841
+ resolve({ ...parsed, rawOutput, parseMethod: "stdout-JSON" });
1842
+ return;
1843
+ } catch (e) {
1844
+ debug("vitest", "stdout JSON \u89E3\u6790\u5931\u8D25:", e instanceof Error ? e.message : String(e));
1845
+ }
1846
+ debug("vitest", "\u5C1D\u8BD5\u4ECE\u6587\u672C\u8F93\u51FA\u89E3\u6790...");
1847
+ if (rawOutput) {
1848
+ const parsed = parseVitestTextOutput(rawOutput, !!error);
1849
+ debug("vitest", "\u6587\u672C\u89E3\u6790\u7ED3\u679C:", parsed.suites.length, "\u4E2A\u5957\u4EF6");
1850
+ resolve({ ...parsed, rawOutput, parseMethod: "text-fallback" });
1851
+ return;
1828
1852
  }
1853
+ if (error && error.message.includes("ENOENT")) {
1854
+ reject(new Error("\u672A\u627E\u5230 vitest\uFF0C\u8BF7\u786E\u4FDD\u5DF2\u5B89\u88C5: npm install -D vitest"));
1855
+ return;
1856
+ }
1857
+ debug("vitest", "\u6240\u6709\u89E3\u6790\u65B9\u5F0F\u5747\u5931\u8D25\uFF0C\u8FD4\u56DE\u7A7A\u7ED3\u679C");
1858
+ resolve({ success: !error, suites: [], rawOutput, parseMethod: "none" });
1829
1859
  });
1830
1860
  child.on("error", (err) => {
1831
1861
  try {
1832
- fs9.unlinkSync(tmpFile);
1862
+ import_node_fs6.default.unlinkSync(tmpFile);
1833
1863
  } catch {
1834
1864
  }
1835
1865
  reject(new Error(`Vitest \u6267\u884C\u5931\u8D25: ${err.message}`));
1836
1866
  });
1837
1867
  });
1838
1868
  }
1839
- function parseVitestJSONResult(jsonStr) {
1869
+ function parseVitestJSON(jsonStr) {
1840
1870
  const data = JSON.parse(jsonStr);
1841
1871
  const suites = [];
1872
+ debug("vitest-json", "JSON \u9876\u5C42\u5B57\u6BB5:", Object.keys(data).join(", "));
1842
1873
  if (data.testResults && Array.isArray(data.testResults)) {
1874
+ debug("vitest-json", `testResults \u6570\u91CF: ${data.testResults.length}`);
1843
1875
  for (const fileResult of data.testResults) {
1876
+ const suiteTests = parseTestResults(fileResult);
1877
+ suites.push({
1878
+ name: import_node_path6.default.basename(fileResult.name || "unknown"),
1879
+ file: fileResult.name || "unknown",
1880
+ type: "unit",
1881
+ status: mapVitestStatus(fileResult.status),
1882
+ duration: fileResult.duration || 0,
1883
+ tests: suiteTests
1884
+ });
1885
+ }
1886
+ }
1887
+ if (suites.length === 0 && data.numTotalTests !== void 0) {
1888
+ debug("vitest-json", `\u4F7F\u7528\u6C47\u603B\u683C\u5F0F: total=${data.numTotalTests}, passed=${data.numPassedTests}`);
1889
+ suites.push({
1890
+ name: "Vitest Results",
1891
+ file: "unknown",
1892
+ type: "unit",
1893
+ status: data.numFailedTests > 0 ? "failed" : "passed",
1894
+ duration: 0,
1895
+ tests: buildTestsFromSummary(data)
1896
+ });
1897
+ }
1898
+ if (suites.length === 0 && data.suites && Array.isArray(data.suites)) {
1899
+ debug("vitest-json", `suites \u6570\u91CF: ${data.suites.length}`);
1900
+ for (const suiteData of data.suites) {
1844
1901
  const suiteTests = [];
1845
- const assertions = fileResult.assertionResults || fileResult.tests || [];
1846
- for (const assertion of assertions) {
1902
+ for (const test of suiteData.tests || []) {
1847
1903
  suiteTests.push({
1848
- name: assertion.title || assertion.fullName || assertion.name || "unknown",
1849
- file: fileResult.name || "unknown",
1850
- status: mapVitestStatus(assertion.status),
1851
- duration: assertion.duration || 0,
1852
- error: assertion.failureMessages?.length ? { message: assertion.failureMessages[0] } : assertion.failureMessage ? { message: assertion.failureMessage } : void 0,
1904
+ name: test.name || test.title || "unknown",
1905
+ file: test.file || suiteData.file || "unknown",
1906
+ status: mapVitestStatus(test.status || test.result?.status),
1907
+ duration: test.duration || test.result?.duration || 0,
1908
+ error: test.result?.errors?.[0] ? { message: test.result.errors[0].message || String(test.result.errors[0]) } : void 0,
1853
1909
  retries: 0
1854
1910
  });
1855
1911
  }
1856
- if (suiteTests.length === 0 && fileResult.numPassingTests !== void 0) {
1857
- const counts = [
1858
- { n: fileResult.numPassingTests || 0, s: "passed" },
1859
- { n: fileResult.numFailingTests || 0, s: "failed" },
1860
- { n: fileResult.numPendingTests || 0, s: "skipped" }
1861
- ];
1862
- for (const { n, s } of counts) {
1863
- for (let i = 0; i < n; i++) {
1864
- suiteTests.push({
1865
- name: `${s} test ${i + 1}`,
1866
- file: fileResult.name || "unknown",
1867
- status: s,
1868
- duration: 0,
1869
- retries: 0
1870
- });
1871
- }
1872
- }
1873
- }
1874
1912
  suites.push({
1875
- name: import_node_path6.default.basename(fileResult.name || "unknown"),
1876
- file: fileResult.name || "unknown",
1913
+ name: suiteData.name || "unknown",
1914
+ file: suiteData.file || "unknown",
1877
1915
  type: "unit",
1878
- status: mapVitestStatus(fileResult.status),
1879
- duration: fileResult.duration || 0,
1916
+ status: suiteTests.some((t) => t.status === "failed") ? "failed" : "passed",
1917
+ duration: 0,
1880
1918
  tests: suiteTests
1881
1919
  });
1882
1920
  }
@@ -1885,58 +1923,101 @@ function parseVitestJSONResult(jsonStr) {
1885
1923
  if (data.coverageMap) {
1886
1924
  coverage = extractCoverage(data.coverageMap);
1887
1925
  }
1888
- const success = data.success !== false && data.numFailedTests === void 0 ? suites.every((s) => s.status !== "failed") : (data.numFailedTests || 0) === 0;
1926
+ if (!coverage && data.coverage && typeof data.coverage === "object") {
1927
+ const cov = data.coverage;
1928
+ const totals = cov.totals || cov;
1929
+ const getVal = (key) => {
1930
+ const v = totals[key];
1931
+ return typeof v === "number" ? v : typeof v === "object" && v !== null && "pct" in v ? v.pct / 100 : 0;
1932
+ };
1933
+ coverage = {
1934
+ lines: getVal("lines"),
1935
+ statements: getVal("statements"),
1936
+ functions: getVal("functions"),
1937
+ branches: getVal("branches")
1938
+ };
1939
+ }
1940
+ const success = data.success !== false ? data.numFailedTests !== void 0 ? data.numFailedTests === 0 : suites.every((s) => s.status !== "failed") : false;
1889
1941
  return { success, suites, coverage };
1890
1942
  }
1891
- function parseVitestJSONOutput(output) {
1892
- const jsonMatch = output.match(/\{[\s\S]*"testResults"[\s\S]*\}/);
1893
- if (!jsonMatch) {
1894
- return parseVitestTextOutput(output, false);
1943
+ function parseTestResults(fileResult) {
1944
+ const tests = [];
1945
+ const assertions = fileResult.assertionResults || fileResult.tests || [];
1946
+ for (const assertion of assertions) {
1947
+ tests.push({
1948
+ name: assertion.title || assertion.fullName || assertion.name || "unknown",
1949
+ file: fileResult.name || "unknown",
1950
+ status: mapVitestStatus(assertion.status),
1951
+ duration: assertion.duration || 0,
1952
+ error: assertion.failureMessages?.length ? { message: assertion.failureMessages[0] } : assertion.failureMessage ? { message: assertion.failureMessage } : void 0,
1953
+ retries: 0
1954
+ });
1895
1955
  }
1896
- try {
1956
+ if (tests.length === 0 && fileResult.numPassingTests !== void 0) {
1957
+ tests.push(...buildTestsFromSummary(fileResult));
1958
+ }
1959
+ return tests;
1960
+ }
1961
+ function buildTestsFromSummary(data) {
1962
+ const tests = [];
1963
+ const counts = [
1964
+ [data.numPassedTests || 0, "passed"],
1965
+ [data.numFailedTests || 0, "failed"],
1966
+ [data.numPendingTests || 0, "skipped"]
1967
+ ];
1968
+ for (const [n, s] of counts) {
1969
+ for (let i = 0; i < n; i++) {
1970
+ tests.push({
1971
+ name: `${s} test ${i + 1}`,
1972
+ file: data.name || "unknown",
1973
+ status: s,
1974
+ duration: 0,
1975
+ retries: 0
1976
+ });
1977
+ }
1978
+ }
1979
+ return tests;
1980
+ }
1981
+ function parseFromStdout(output) {
1982
+ const jsonMatch = output.match(/\{[\s\S]*"testResults"[\s\S]*\}/);
1983
+ if (jsonMatch) {
1897
1984
  const data = JSON.parse(jsonMatch[0]);
1898
1985
  const suites = [];
1899
1986
  if (data.testResults && Array.isArray(data.testResults)) {
1900
1987
  for (const fileResult of data.testResults) {
1901
- const suite = {
1902
- name: import_node_path6.default.basename(fileResult.name || fileResult.assertionResults?.[0]?.ancestorTitles?.[0] || "unknown"),
1988
+ suites.push({
1989
+ name: import_node_path6.default.basename(fileResult.name || "unknown"),
1903
1990
  file: fileResult.name || "unknown",
1904
1991
  type: "unit",
1905
1992
  status: mapVitestStatus(fileResult.status),
1906
1993
  duration: fileResult.duration || 0,
1907
- tests: (fileResult.assertionResults || []).map((assertion) => ({
1908
- name: assertion.title || assertion.fullName || "unknown",
1909
- file: fileResult.name || "unknown",
1910
- status: mapVitestStatus(assertion.status),
1911
- duration: assertion.duration || 0,
1912
- error: assertion.failureMessages?.length ? { message: assertion.failureMessages[0] } : void 0,
1913
- retries: 0
1914
- }))
1915
- };
1916
- suites.push(suite);
1994
+ tests: parseTestResults(fileResult)
1995
+ });
1917
1996
  }
1918
1997
  }
1919
- let coverage;
1920
- if (data.coverageMap) {
1921
- coverage = extractCoverage(data.coverageMap);
1922
- }
1923
1998
  const success = data.success !== false && suites.every((s) => s.status !== "failed");
1999
+ let coverage;
2000
+ if (data.coverageMap) coverage = extractCoverage(data.coverageMap);
1924
2001
  return { success, suites, coverage };
1925
- } catch {
1926
- return parseVitestTextOutput(output, false);
1927
2002
  }
2003
+ const anyJsonMatch = output.match(/\{[\s\S]*"numTotalTests"[\s\S]*\}/);
2004
+ if (anyJsonMatch) {
2005
+ return parseVitestJSON(anyJsonMatch[0]);
2006
+ }
2007
+ throw new Error("stdout \u4E2D\u672A\u627E\u5230\u6709\u6548 JSON");
1928
2008
  }
1929
2009
  function parseVitestTextOutput(output, hasError) {
1930
2010
  const suites = [];
2011
+ debug("vitest-text", "\u6587\u672C\u8F93\u51FA\u524D 1000 \u5B57\u7B26:", output.substring(0, 1e3));
2012
+ const suiteRegex = /[✓✗×✕]\s+(.+\.test\.(ts|js)|.+\.spec\.(ts|js))\s*\((\d+)[^)]*\)/i;
2013
+ const lines = output.split("\n");
1931
2014
  let totalPassed = 0;
1932
2015
  let totalFailed = 0;
1933
- const suiteRegex = /[✓✗×]\s+(.+\.test\.ts|.+\.spec\.ts)\s*\((\d+)\s+test/i;
1934
- const lines = output.split("\n");
1935
2016
  for (const line of lines) {
1936
2017
  const match = line.match(suiteRegex);
1937
2018
  if (match) {
1938
2019
  const file = match[1];
1939
- const testCount = parseInt(match[2], 10);
2020
+ const testCount = parseInt(match[4], 10);
1940
2021
  const isPassed = line.includes("\u2713");
1941
2022
  if (isPassed) totalPassed += testCount;
1942
2023
  else totalFailed += testCount;
@@ -1956,15 +2037,39 @@ function parseVitestTextOutput(output, hasError) {
1956
2037
  });
1957
2038
  }
1958
2039
  }
2040
+ if (suites.length === 0) {
2041
+ const summaryMatch = output.match(/Tests\s+(\d+)\s+(passed|failed)/i);
2042
+ if (summaryMatch) {
2043
+ const count = parseInt(summaryMatch[1], 10);
2044
+ const status = summaryMatch[2].toLowerCase() === "passed" ? "passed" : "failed";
2045
+ suites.push({
2046
+ name: "Vitest Summary",
2047
+ file: "unknown",
2048
+ type: "unit",
2049
+ status,
2050
+ duration: 0,
2051
+ tests: Array.from({ length: count }, (_, i) => ({
2052
+ name: `test ${i + 1}`,
2053
+ file: "unknown",
2054
+ status,
2055
+ duration: 0,
2056
+ retries: 0
2057
+ }))
2058
+ });
2059
+ }
2060
+ }
2061
+ debug("vitest-text", `\u89E3\u6790\u5230 ${suites.length} \u4E2A\u5957\u4EF6, ${totalPassed} \u901A\u8FC7, ${totalFailed} \u5931\u8D25`);
1959
2062
  return {
1960
2063
  success: !hasError || totalFailed === 0,
1961
2064
  suites
1962
2065
  };
1963
2066
  }
1964
2067
  function mapVitestStatus(status) {
2068
+ if (!status) return "pending";
1965
2069
  switch (status) {
1966
2070
  case "passed":
1967
2071
  case "pass":
2072
+ case "done":
1968
2073
  return "passed";
1969
2074
  case "failed":
1970
2075
  case "fail":
@@ -1972,6 +2077,7 @@ function mapVitestStatus(status) {
1972
2077
  case "skipped":
1973
2078
  case "skip":
1974
2079
  case "pending":
2080
+ case "todo":
1975
2081
  return "skipped";
1976
2082
  default:
1977
2083
  return "pending";
@@ -2908,7 +3014,7 @@ async function testAIConnection(config) {
2908
3014
  }
2909
3015
 
2910
3016
  // src/services/mock-server.ts
2911
- var import_node_fs6 = __toESM(require("fs"), 1);
3017
+ var import_node_fs7 = __toESM(require("fs"), 1);
2912
3018
  var import_node_path8 = __toESM(require("path"), 1);
2913
3019
  var serverState = {
2914
3020
  running: false,
@@ -2921,18 +3027,18 @@ function getMockServerState() {
2921
3027
  }
2922
3028
  async function loadMockRoutes(routesDir) {
2923
3029
  const absDir = import_node_path8.default.resolve(process.cwd(), routesDir);
2924
- if (!import_node_fs6.default.existsSync(absDir)) {
3030
+ if (!import_node_fs7.default.existsSync(absDir)) {
2925
3031
  return [];
2926
3032
  }
2927
3033
  const routes = [];
2928
- const entries = import_node_fs6.default.readdirSync(absDir, { withFileTypes: true });
3034
+ const entries = import_node_fs7.default.readdirSync(absDir, { withFileTypes: true });
2929
3035
  for (const entry of entries) {
2930
3036
  if (!entry.isFile()) continue;
2931
3037
  const filePath = import_node_path8.default.join(absDir, entry.name);
2932
3038
  const ext = import_node_path8.default.extname(entry.name);
2933
3039
  try {
2934
3040
  if (ext === ".json") {
2935
- const content = import_node_fs6.default.readFileSync(filePath, "utf-8");
3041
+ const content = import_node_fs7.default.readFileSync(filePath, "utf-8");
2936
3042
  const parsed = JSON.parse(content);
2937
3043
  if (Array.isArray(parsed)) {
2938
3044
  routes.push(...parsed);
@@ -3124,11 +3230,11 @@ function generateMockRouteTemplate(name) {
3124
3230
  }
3125
3231
  function initMockRoutesDir(routesDir) {
3126
3232
  const absDir = import_node_path8.default.resolve(process.cwd(), routesDir);
3127
- if (!import_node_fs6.default.existsSync(absDir)) {
3128
- import_node_fs6.default.mkdirSync(absDir, { recursive: true });
3233
+ if (!import_node_fs7.default.existsSync(absDir)) {
3234
+ import_node_fs7.default.mkdirSync(absDir, { recursive: true });
3129
3235
  }
3130
3236
  const examplePath = import_node_path8.default.join(absDir, "example.json");
3131
- if (!import_node_fs6.default.existsSync(examplePath)) {
3237
+ if (!import_node_fs7.default.existsSync(examplePath)) {
3132
3238
  const exampleRoutes = [
3133
3239
  {
3134
3240
  method: "GET",
@@ -3152,24 +3258,24 @@ function initMockRoutesDir(routesDir) {
3152
3258
  }
3153
3259
  }
3154
3260
  ];
3155
- import_node_fs6.default.writeFileSync(examplePath, JSON.stringify(exampleRoutes, null, 2), "utf-8");
3261
+ import_node_fs7.default.writeFileSync(examplePath, JSON.stringify(exampleRoutes, null, 2), "utf-8");
3156
3262
  }
3157
3263
  }
3158
3264
 
3159
3265
  // src/services/visual.ts
3160
- var import_node_fs7 = __toESM(require("fs"), 1);
3266
+ var import_node_fs8 = __toESM(require("fs"), 1);
3161
3267
  var import_node_path9 = __toESM(require("path"), 1);
3162
3268
  var import_pixelmatch = __toESM(require("pixelmatch"), 1);
3163
3269
  var import_pngjs = require("pngjs");
3164
3270
  function compareImages(baselinePath, currentPath, diffOutputPath, threshold = 0.1) {
3165
- if (!import_node_fs7.default.existsSync(baselinePath)) {
3271
+ if (!import_node_fs8.default.existsSync(baselinePath)) {
3166
3272
  throw new Error(`\u57FA\u7EBF\u56FE\u7247\u4E0D\u5B58\u5728: ${baselinePath}`);
3167
3273
  }
3168
- if (!import_node_fs7.default.existsSync(currentPath)) {
3274
+ if (!import_node_fs8.default.existsSync(currentPath)) {
3169
3275
  throw new Error(`\u5F53\u524D\u56FE\u7247\u4E0D\u5B58\u5728: ${currentPath}`);
3170
3276
  }
3171
- const baseline = import_pngjs.PNG.sync.read(import_node_fs7.default.readFileSync(baselinePath));
3172
- const current = import_pngjs.PNG.sync.read(import_node_fs7.default.readFileSync(currentPath));
3277
+ const baseline = import_pngjs.PNG.sync.read(import_node_fs8.default.readFileSync(baselinePath));
3278
+ const current = import_pngjs.PNG.sync.read(import_node_fs8.default.readFileSync(currentPath));
3173
3279
  if (baseline.width !== current.width || baseline.height !== current.height) {
3174
3280
  return {
3175
3281
  passed: false,
@@ -3198,10 +3304,10 @@ function compareImages(baselinePath, currentPath, diffOutputPath, threshold = 0.
3198
3304
  let diffPath;
3199
3305
  if (diffPixels > 0) {
3200
3306
  const diffDir = import_node_path9.default.dirname(diffOutputPath);
3201
- if (!import_node_fs7.default.existsSync(diffDir)) {
3202
- import_node_fs7.default.mkdirSync(diffDir, { recursive: true });
3307
+ if (!import_node_fs8.default.existsSync(diffDir)) {
3308
+ import_node_fs8.default.mkdirSync(diffDir, { recursive: true });
3203
3309
  }
3204
- import_node_fs7.default.writeFileSync(diffOutputPath, import_pngjs.PNG.sync.write(diff));
3310
+ import_node_fs8.default.writeFileSync(diffOutputPath, import_pngjs.PNG.sync.write(diff));
3205
3311
  diffPath = diffOutputPath;
3206
3312
  }
3207
3313
  return {
@@ -3215,14 +3321,14 @@ function compareImages(baselinePath, currentPath, diffOutputPath, threshold = 0.
3215
3321
  };
3216
3322
  }
3217
3323
  function createBaseline(currentPath, baselinePath) {
3218
- if (!import_node_fs7.default.existsSync(currentPath)) {
3324
+ if (!import_node_fs8.default.existsSync(currentPath)) {
3219
3325
  throw new Error(`\u5F53\u524D\u622A\u56FE\u4E0D\u5B58\u5728: ${currentPath}`);
3220
3326
  }
3221
3327
  const baselineDir = import_node_path9.default.dirname(baselinePath);
3222
- if (!import_node_fs7.default.existsSync(baselineDir)) {
3223
- import_node_fs7.default.mkdirSync(baselineDir, { recursive: true });
3328
+ if (!import_node_fs8.default.existsSync(baselineDir)) {
3329
+ import_node_fs8.default.mkdirSync(baselineDir, { recursive: true });
3224
3330
  }
3225
- import_node_fs7.default.copyFileSync(currentPath, baselinePath);
3331
+ import_node_fs8.default.copyFileSync(currentPath, baselinePath);
3226
3332
  return baselinePath;
3227
3333
  }
3228
3334
  function updateBaseline(currentPath, baselinePath) {
@@ -3230,69 +3336,69 @@ function updateBaseline(currentPath, baselinePath) {
3230
3336
  }
3231
3337
  function updateAllBaselines(currentDir, baselineDir) {
3232
3338
  const updated = [];
3233
- if (!import_node_fs7.default.existsSync(currentDir)) {
3339
+ if (!import_node_fs8.default.existsSync(currentDir)) {
3234
3340
  return updated;
3235
3341
  }
3236
- const files = import_node_fs7.default.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
3342
+ const files = import_node_fs8.default.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
3237
3343
  for (const file of files) {
3238
3344
  const currentPath = import_node_path9.default.join(currentDir, file);
3239
3345
  const baselinePath = import_node_path9.default.join(baselineDir, file);
3240
3346
  const baselineDirAbs = import_node_path9.default.dirname(baselinePath);
3241
- if (!import_node_fs7.default.existsSync(baselineDirAbs)) {
3242
- import_node_fs7.default.mkdirSync(baselineDirAbs, { recursive: true });
3347
+ if (!import_node_fs8.default.existsSync(baselineDirAbs)) {
3348
+ import_node_fs8.default.mkdirSync(baselineDirAbs, { recursive: true });
3243
3349
  }
3244
- import_node_fs7.default.copyFileSync(currentPath, baselinePath);
3350
+ import_node_fs8.default.copyFileSync(currentPath, baselinePath);
3245
3351
  updated.push(file);
3246
3352
  }
3247
3353
  return updated;
3248
3354
  }
3249
3355
  function cleanBaselines(baselineDir) {
3250
- if (!import_node_fs7.default.existsSync(baselineDir)) {
3356
+ if (!import_node_fs8.default.existsSync(baselineDir)) {
3251
3357
  return 0;
3252
3358
  }
3253
- const files = import_node_fs7.default.readdirSync(baselineDir).filter((f) => f.endsWith(".png"));
3359
+ const files = import_node_fs8.default.readdirSync(baselineDir).filter((f) => f.endsWith(".png"));
3254
3360
  let count = 0;
3255
3361
  for (const file of files) {
3256
- import_node_fs7.default.unlinkSync(import_node_path9.default.join(baselineDir, file));
3362
+ import_node_fs8.default.unlinkSync(import_node_path9.default.join(baselineDir, file));
3257
3363
  count++;
3258
3364
  }
3259
3365
  return count;
3260
3366
  }
3261
3367
  function cleanDiffs(diffDir) {
3262
- if (!import_node_fs7.default.existsSync(diffDir)) {
3368
+ if (!import_node_fs8.default.existsSync(diffDir)) {
3263
3369
  return 0;
3264
3370
  }
3265
- const files = import_node_fs7.default.readdirSync(diffDir).filter((f) => f.endsWith(".png"));
3371
+ const files = import_node_fs8.default.readdirSync(diffDir).filter((f) => f.endsWith(".png"));
3266
3372
  let count = 0;
3267
3373
  for (const file of files) {
3268
- import_node_fs7.default.unlinkSync(import_node_path9.default.join(diffDir, file));
3374
+ import_node_fs8.default.unlinkSync(import_node_path9.default.join(diffDir, file));
3269
3375
  count++;
3270
3376
  }
3271
3377
  return count;
3272
3378
  }
3273
3379
  function listBaselines(baselineDir) {
3274
- if (!import_node_fs7.default.existsSync(baselineDir)) {
3380
+ if (!import_node_fs8.default.existsSync(baselineDir)) {
3275
3381
  return [];
3276
3382
  }
3277
- return import_node_fs7.default.readdirSync(baselineDir).filter((f) => f.endsWith(".png")).sort();
3383
+ return import_node_fs8.default.readdirSync(baselineDir).filter((f) => f.endsWith(".png")).sort();
3278
3384
  }
3279
3385
  function listDiffs(diffDir) {
3280
- if (!import_node_fs7.default.existsSync(diffDir)) {
3386
+ if (!import_node_fs8.default.existsSync(diffDir)) {
3281
3387
  return [];
3282
3388
  }
3283
- return import_node_fs7.default.readdirSync(diffDir).filter((f) => f.endsWith(".png")).sort();
3389
+ return import_node_fs8.default.readdirSync(diffDir).filter((f) => f.endsWith(".png")).sort();
3284
3390
  }
3285
3391
  function compareDirectories(baselineDir, currentDir, diffDir, threshold = 0.1) {
3286
3392
  const results = [];
3287
- if (!import_node_fs7.default.existsSync(currentDir)) {
3393
+ if (!import_node_fs8.default.existsSync(currentDir)) {
3288
3394
  return results;
3289
3395
  }
3290
- const currentFiles = import_node_fs7.default.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
3396
+ const currentFiles = import_node_fs8.default.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
3291
3397
  for (const file of currentFiles) {
3292
3398
  const currentPath = import_node_path9.default.join(currentDir, file);
3293
3399
  const baselinePath = import_node_path9.default.join(baselineDir, file);
3294
3400
  const diffPath = import_node_path9.default.join(diffDir, file);
3295
- if (!import_node_fs7.default.existsSync(baselinePath)) {
3401
+ if (!import_node_fs8.default.existsSync(baselinePath)) {
3296
3402
  createBaseline(currentPath, baselinePath);
3297
3403
  results.push({
3298
3404
  passed: true,
@@ -3324,14 +3430,14 @@ function compareDirectories(baselineDir, currentDir, diffDir, threshold = 0.1) {
3324
3430
  }
3325
3431
 
3326
3432
  // src/services/source-analyzer.ts
3327
- var import_node_fs8 = __toESM(require("fs"), 1);
3433
+ var import_node_fs9 = __toESM(require("fs"), 1);
3328
3434
  var import_node_path10 = __toESM(require("path"), 1);
3329
3435
  function analyzeFile(filePath) {
3330
3436
  const absolutePath = import_node_path10.default.resolve(process.cwd(), filePath);
3331
- if (!import_node_fs8.default.existsSync(absolutePath)) {
3437
+ if (!import_node_fs9.default.existsSync(absolutePath)) {
3332
3438
  return { filePath, exports: [], apiCalls: [] };
3333
3439
  }
3334
- const content = import_node_fs8.default.readFileSync(absolutePath, "utf-8");
3440
+ const content = import_node_fs9.default.readFileSync(absolutePath, "utf-8");
3335
3441
  const ext = import_node_path10.default.extname(filePath);
3336
3442
  const result = {
3337
3443
  filePath,
@@ -3686,13 +3792,13 @@ function cleanTemplateUrl(url) {
3686
3792
  }
3687
3793
  function scanAPICalls(srcDir) {
3688
3794
  const absDir = import_node_path10.default.resolve(process.cwd(), srcDir);
3689
- if (!import_node_fs8.default.existsSync(absDir)) {
3795
+ if (!import_node_fs9.default.existsSync(absDir)) {
3690
3796
  return [];
3691
3797
  }
3692
3798
  const allCalls = [];
3693
3799
  const seen = /* @__PURE__ */ new Set();
3694
3800
  function walk(dir) {
3695
- const entries = import_node_fs8.default.readdirSync(dir, { withFileTypes: true });
3801
+ const entries = import_node_fs9.default.readdirSync(dir, { withFileTypes: true });
3696
3802
  for (const entry of entries) {
3697
3803
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist") continue;
3698
3804
  const fullPath = import_node_path10.default.join(dir, entry.name);
@@ -3700,7 +3806,7 @@ function scanAPICalls(srcDir) {
3700
3806
  walk(fullPath);
3701
3807
  } else if (entry.isFile() && /\.(ts|js|vue|mjs)$/.test(entry.name)) {
3702
3808
  try {
3703
- const content = import_node_fs8.default.readFileSync(fullPath, "utf-8");
3809
+ const content = import_node_fs9.default.readFileSync(fullPath, "utf-8");
3704
3810
  const calls = extractAPICalls(content, import_node_path10.default.relative(process.cwd(), fullPath));
3705
3811
  for (const call of calls) {
3706
3812
  const key = `${call.method}:${call.url}`;