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.js CHANGED
@@ -1623,12 +1623,23 @@ function generateHTMLReport(data) {
1623
1623
  // src/runners/vitest-runner.ts
1624
1624
  import { execFile } from "child_process";
1625
1625
  import path5 from "path";
1626
+ import fs6 from "fs";
1627
+ import os from "os";
1628
+ var isVerbose = () => process.env.QAT_VERBOSE === "true";
1629
+ function debug(label, ...args) {
1630
+ if (isVerbose()) {
1631
+ console.log(`\x1B[90m [debug:${label}]\x1B[0m`, ...args);
1632
+ }
1633
+ }
1626
1634
  async function runVitest(options) {
1627
1635
  const startTime = Date.now();
1628
1636
  const args = buildVitestArgs(options);
1637
+ debug("vitest", "\u547D\u4EE4\u53C2\u6570:", args.join(" "));
1629
1638
  try {
1630
1639
  const result = await execVitest(args);
1631
1640
  const endTime = Date.now();
1641
+ 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`);
1642
+ debug("vitest", "\u89E3\u6790\u65B9\u5F0F:", result.parseMethod);
1632
1643
  return {
1633
1644
  type: options.type,
1634
1645
  status: result.success ? "passed" : "failed",
@@ -1693,12 +1704,11 @@ function buildVitestArgs(options) {
1693
1704
  return args;
1694
1705
  }
1695
1706
  async function execVitest(args) {
1696
- const os = await import("os");
1697
- const fs9 = await import("fs");
1698
1707
  const tmpFile = path5.join(os.tmpdir(), `qat-vitest-result-${Date.now()}.json`);
1699
1708
  const argsWithOutput = [...args, "--outputFile", tmpFile];
1700
1709
  return new Promise((resolve, reject) => {
1701
1710
  const npx = process.platform === "win32" ? "npx.cmd" : "npx";
1711
+ debug("vitest", "\u6267\u884C\u547D\u4EE4:", npx, argsWithOutput.join(" "));
1702
1712
  const child = execFile(npx, argsWithOutput, {
1703
1713
  cwd: process.cwd(),
1704
1714
  env: { ...process.env, FORCE_COLOR: "0", NO_COLOR: "1" },
@@ -1706,85 +1716,113 @@ async function execVitest(args) {
1706
1716
  shell: true
1707
1717
  }, (error, stdout, stderr) => {
1708
1718
  const rawOutput = stdout || stderr || "";
1719
+ const exitCode = error && "code" in error ? error.code : 0;
1720
+ debug("vitest", `\u9000\u51FA\u7801: ${exitCode}`);
1721
+ debug("vitest", `stdout \u957F\u5EA6: ${stdout?.length || 0}, stderr \u957F\u5EA6: ${stderr?.length || 0}`);
1709
1722
  let jsonResult = null;
1710
1723
  try {
1711
- if (fs9.existsSync(tmpFile)) {
1712
- jsonResult = fs9.readFileSync(tmpFile, "utf-8");
1713
- fs9.unlinkSync(tmpFile);
1724
+ if (fs6.existsSync(tmpFile)) {
1725
+ jsonResult = fs6.readFileSync(tmpFile, "utf-8");
1726
+ debug("vitest", `\u4ECE\u4E34\u65F6\u6587\u4EF6\u8BFB\u53D6\u5230 JSON (${jsonResult.length} \u5B57\u7B26)`);
1727
+ debug("vitest", "JSON \u524D 500 \u5B57\u7B26:", jsonResult.substring(0, 500));
1728
+ fs6.unlinkSync(tmpFile);
1729
+ } else {
1730
+ debug("vitest", "\u4E34\u65F6\u6587\u4EF6\u4E0D\u5B58\u5728:", tmpFile);
1714
1731
  }
1715
- } catch {
1732
+ } catch (e) {
1733
+ debug("vitest", "\u4E34\u65F6\u6587\u4EF6\u8BFB\u53D6\u5931\u8D25:", e instanceof Error ? e.message : String(e));
1716
1734
  }
1717
1735
  if (jsonResult) {
1718
1736
  try {
1719
- const parsed = parseVitestJSONResult(jsonResult);
1720
- resolve({ ...parsed, rawOutput });
1737
+ const parsed = parseVitestJSON(jsonResult);
1738
+ debug("vitest", "\u4ECE\u4E34\u65F6\u6587\u4EF6\u89E3\u6790\u6210\u529F:", parsed.suites.length, "\u4E2A\u5957\u4EF6");
1739
+ resolve({ ...parsed, rawOutput, parseMethod: "outputFile-JSON" });
1721
1740
  return;
1722
- } catch {
1741
+ } catch (e) {
1742
+ debug("vitest", "\u4E34\u65F6\u6587\u4EF6 JSON \u89E3\u6790\u5931\u8D25:", e instanceof Error ? e.message : String(e));
1723
1743
  }
1724
1744
  }
1745
+ debug("vitest", "\u5C1D\u8BD5\u4ECE stdout \u63D0\u53D6 JSON...");
1725
1746
  try {
1726
- const parsed = parseVitestJSONOutput(rawOutput);
1727
- resolve({ ...parsed, rawOutput });
1728
- } catch {
1729
- if (rawOutput) {
1730
- resolve({ ...parseVitestTextOutput(rawOutput, !!error), rawOutput });
1731
- } else if (error && error.message.includes("ENOENT")) {
1732
- reject(new Error("\u672A\u627E\u5230 vitest\uFF0C\u8BF7\u786E\u4FDD\u5DF2\u5B89\u88C5: npm install -D vitest"));
1733
- } else {
1734
- resolve({ success: !error, suites: [], rawOutput });
1735
- }
1747
+ const parsed = parseFromStdout(rawOutput);
1748
+ debug("vitest", "\u4ECE stdout \u89E3\u6790\u6210\u529F:", parsed.suites.length, "\u4E2A\u5957\u4EF6");
1749
+ resolve({ ...parsed, rawOutput, parseMethod: "stdout-JSON" });
1750
+ return;
1751
+ } catch (e) {
1752
+ debug("vitest", "stdout JSON \u89E3\u6790\u5931\u8D25:", e instanceof Error ? e.message : String(e));
1753
+ }
1754
+ debug("vitest", "\u5C1D\u8BD5\u4ECE\u6587\u672C\u8F93\u51FA\u89E3\u6790...");
1755
+ if (rawOutput) {
1756
+ const parsed = parseVitestTextOutput(rawOutput, !!error);
1757
+ debug("vitest", "\u6587\u672C\u89E3\u6790\u7ED3\u679C:", parsed.suites.length, "\u4E2A\u5957\u4EF6");
1758
+ resolve({ ...parsed, rawOutput, parseMethod: "text-fallback" });
1759
+ return;
1736
1760
  }
1761
+ if (error && error.message.includes("ENOENT")) {
1762
+ reject(new Error("\u672A\u627E\u5230 vitest\uFF0C\u8BF7\u786E\u4FDD\u5DF2\u5B89\u88C5: npm install -D vitest"));
1763
+ return;
1764
+ }
1765
+ debug("vitest", "\u6240\u6709\u89E3\u6790\u65B9\u5F0F\u5747\u5931\u8D25\uFF0C\u8FD4\u56DE\u7A7A\u7ED3\u679C");
1766
+ resolve({ success: !error, suites: [], rawOutput, parseMethod: "none" });
1737
1767
  });
1738
1768
  child.on("error", (err) => {
1739
1769
  try {
1740
- fs9.unlinkSync(tmpFile);
1770
+ fs6.unlinkSync(tmpFile);
1741
1771
  } catch {
1742
1772
  }
1743
1773
  reject(new Error(`Vitest \u6267\u884C\u5931\u8D25: ${err.message}`));
1744
1774
  });
1745
1775
  });
1746
1776
  }
1747
- function parseVitestJSONResult(jsonStr) {
1777
+ function parseVitestJSON(jsonStr) {
1748
1778
  const data = JSON.parse(jsonStr);
1749
1779
  const suites = [];
1780
+ debug("vitest-json", "JSON \u9876\u5C42\u5B57\u6BB5:", Object.keys(data).join(", "));
1750
1781
  if (data.testResults && Array.isArray(data.testResults)) {
1782
+ debug("vitest-json", `testResults \u6570\u91CF: ${data.testResults.length}`);
1751
1783
  for (const fileResult of data.testResults) {
1784
+ const suiteTests = parseTestResults(fileResult);
1785
+ suites.push({
1786
+ name: path5.basename(fileResult.name || "unknown"),
1787
+ file: fileResult.name || "unknown",
1788
+ type: "unit",
1789
+ status: mapVitestStatus(fileResult.status),
1790
+ duration: fileResult.duration || 0,
1791
+ tests: suiteTests
1792
+ });
1793
+ }
1794
+ }
1795
+ if (suites.length === 0 && data.numTotalTests !== void 0) {
1796
+ debug("vitest-json", `\u4F7F\u7528\u6C47\u603B\u683C\u5F0F: total=${data.numTotalTests}, passed=${data.numPassedTests}`);
1797
+ suites.push({
1798
+ name: "Vitest Results",
1799
+ file: "unknown",
1800
+ type: "unit",
1801
+ status: data.numFailedTests > 0 ? "failed" : "passed",
1802
+ duration: 0,
1803
+ tests: buildTestsFromSummary(data)
1804
+ });
1805
+ }
1806
+ if (suites.length === 0 && data.suites && Array.isArray(data.suites)) {
1807
+ debug("vitest-json", `suites \u6570\u91CF: ${data.suites.length}`);
1808
+ for (const suiteData of data.suites) {
1752
1809
  const suiteTests = [];
1753
- const assertions = fileResult.assertionResults || fileResult.tests || [];
1754
- for (const assertion of assertions) {
1810
+ for (const test of suiteData.tests || []) {
1755
1811
  suiteTests.push({
1756
- name: assertion.title || assertion.fullName || assertion.name || "unknown",
1757
- file: fileResult.name || "unknown",
1758
- status: mapVitestStatus(assertion.status),
1759
- duration: assertion.duration || 0,
1760
- error: assertion.failureMessages?.length ? { message: assertion.failureMessages[0] } : assertion.failureMessage ? { message: assertion.failureMessage } : void 0,
1812
+ name: test.name || test.title || "unknown",
1813
+ file: test.file || suiteData.file || "unknown",
1814
+ status: mapVitestStatus(test.status || test.result?.status),
1815
+ duration: test.duration || test.result?.duration || 0,
1816
+ error: test.result?.errors?.[0] ? { message: test.result.errors[0].message || String(test.result.errors[0]) } : void 0,
1761
1817
  retries: 0
1762
1818
  });
1763
1819
  }
1764
- if (suiteTests.length === 0 && fileResult.numPassingTests !== void 0) {
1765
- const counts = [
1766
- { n: fileResult.numPassingTests || 0, s: "passed" },
1767
- { n: fileResult.numFailingTests || 0, s: "failed" },
1768
- { n: fileResult.numPendingTests || 0, s: "skipped" }
1769
- ];
1770
- for (const { n, s } of counts) {
1771
- for (let i = 0; i < n; i++) {
1772
- suiteTests.push({
1773
- name: `${s} test ${i + 1}`,
1774
- file: fileResult.name || "unknown",
1775
- status: s,
1776
- duration: 0,
1777
- retries: 0
1778
- });
1779
- }
1780
- }
1781
- }
1782
1820
  suites.push({
1783
- name: path5.basename(fileResult.name || "unknown"),
1784
- file: fileResult.name || "unknown",
1821
+ name: suiteData.name || "unknown",
1822
+ file: suiteData.file || "unknown",
1785
1823
  type: "unit",
1786
- status: mapVitestStatus(fileResult.status),
1787
- duration: fileResult.duration || 0,
1824
+ status: suiteTests.some((t) => t.status === "failed") ? "failed" : "passed",
1825
+ duration: 0,
1788
1826
  tests: suiteTests
1789
1827
  });
1790
1828
  }
@@ -1793,58 +1831,101 @@ function parseVitestJSONResult(jsonStr) {
1793
1831
  if (data.coverageMap) {
1794
1832
  coverage = extractCoverage(data.coverageMap);
1795
1833
  }
1796
- const success = data.success !== false && data.numFailedTests === void 0 ? suites.every((s) => s.status !== "failed") : (data.numFailedTests || 0) === 0;
1834
+ if (!coverage && data.coverage && typeof data.coverage === "object") {
1835
+ const cov = data.coverage;
1836
+ const totals = cov.totals || cov;
1837
+ const getVal = (key) => {
1838
+ const v = totals[key];
1839
+ return typeof v === "number" ? v : typeof v === "object" && v !== null && "pct" in v ? v.pct / 100 : 0;
1840
+ };
1841
+ coverage = {
1842
+ lines: getVal("lines"),
1843
+ statements: getVal("statements"),
1844
+ functions: getVal("functions"),
1845
+ branches: getVal("branches")
1846
+ };
1847
+ }
1848
+ const success = data.success !== false ? data.numFailedTests !== void 0 ? data.numFailedTests === 0 : suites.every((s) => s.status !== "failed") : false;
1797
1849
  return { success, suites, coverage };
1798
1850
  }
1799
- function parseVitestJSONOutput(output) {
1800
- const jsonMatch = output.match(/\{[\s\S]*"testResults"[\s\S]*\}/);
1801
- if (!jsonMatch) {
1802
- return parseVitestTextOutput(output, false);
1851
+ function parseTestResults(fileResult) {
1852
+ const tests = [];
1853
+ const assertions = fileResult.assertionResults || fileResult.tests || [];
1854
+ for (const assertion of assertions) {
1855
+ tests.push({
1856
+ name: assertion.title || assertion.fullName || assertion.name || "unknown",
1857
+ file: fileResult.name || "unknown",
1858
+ status: mapVitestStatus(assertion.status),
1859
+ duration: assertion.duration || 0,
1860
+ error: assertion.failureMessages?.length ? { message: assertion.failureMessages[0] } : assertion.failureMessage ? { message: assertion.failureMessage } : void 0,
1861
+ retries: 0
1862
+ });
1803
1863
  }
1804
- try {
1864
+ if (tests.length === 0 && fileResult.numPassingTests !== void 0) {
1865
+ tests.push(...buildTestsFromSummary(fileResult));
1866
+ }
1867
+ return tests;
1868
+ }
1869
+ function buildTestsFromSummary(data) {
1870
+ const tests = [];
1871
+ const counts = [
1872
+ [data.numPassedTests || 0, "passed"],
1873
+ [data.numFailedTests || 0, "failed"],
1874
+ [data.numPendingTests || 0, "skipped"]
1875
+ ];
1876
+ for (const [n, s] of counts) {
1877
+ for (let i = 0; i < n; i++) {
1878
+ tests.push({
1879
+ name: `${s} test ${i + 1}`,
1880
+ file: data.name || "unknown",
1881
+ status: s,
1882
+ duration: 0,
1883
+ retries: 0
1884
+ });
1885
+ }
1886
+ }
1887
+ return tests;
1888
+ }
1889
+ function parseFromStdout(output) {
1890
+ const jsonMatch = output.match(/\{[\s\S]*"testResults"[\s\S]*\}/);
1891
+ if (jsonMatch) {
1805
1892
  const data = JSON.parse(jsonMatch[0]);
1806
1893
  const suites = [];
1807
1894
  if (data.testResults && Array.isArray(data.testResults)) {
1808
1895
  for (const fileResult of data.testResults) {
1809
- const suite = {
1810
- name: path5.basename(fileResult.name || fileResult.assertionResults?.[0]?.ancestorTitles?.[0] || "unknown"),
1896
+ suites.push({
1897
+ name: path5.basename(fileResult.name || "unknown"),
1811
1898
  file: fileResult.name || "unknown",
1812
1899
  type: "unit",
1813
1900
  status: mapVitestStatus(fileResult.status),
1814
1901
  duration: fileResult.duration || 0,
1815
- tests: (fileResult.assertionResults || []).map((assertion) => ({
1816
- name: assertion.title || assertion.fullName || "unknown",
1817
- file: fileResult.name || "unknown",
1818
- status: mapVitestStatus(assertion.status),
1819
- duration: assertion.duration || 0,
1820
- error: assertion.failureMessages?.length ? { message: assertion.failureMessages[0] } : void 0,
1821
- retries: 0
1822
- }))
1823
- };
1824
- suites.push(suite);
1902
+ tests: parseTestResults(fileResult)
1903
+ });
1825
1904
  }
1826
1905
  }
1827
- let coverage;
1828
- if (data.coverageMap) {
1829
- coverage = extractCoverage(data.coverageMap);
1830
- }
1831
1906
  const success = data.success !== false && suites.every((s) => s.status !== "failed");
1907
+ let coverage;
1908
+ if (data.coverageMap) coverage = extractCoverage(data.coverageMap);
1832
1909
  return { success, suites, coverage };
1833
- } catch {
1834
- return parseVitestTextOutput(output, false);
1835
1910
  }
1911
+ const anyJsonMatch = output.match(/\{[\s\S]*"numTotalTests"[\s\S]*\}/);
1912
+ if (anyJsonMatch) {
1913
+ return parseVitestJSON(anyJsonMatch[0]);
1914
+ }
1915
+ throw new Error("stdout \u4E2D\u672A\u627E\u5230\u6709\u6548 JSON");
1836
1916
  }
1837
1917
  function parseVitestTextOutput(output, hasError) {
1838
1918
  const suites = [];
1919
+ debug("vitest-text", "\u6587\u672C\u8F93\u51FA\u524D 1000 \u5B57\u7B26:", output.substring(0, 1e3));
1920
+ const suiteRegex = /[✓✗×✕]\s+(.+\.test\.(ts|js)|.+\.spec\.(ts|js))\s*\((\d+)[^)]*\)/i;
1921
+ const lines = output.split("\n");
1839
1922
  let totalPassed = 0;
1840
1923
  let totalFailed = 0;
1841
- const suiteRegex = /[✓✗×]\s+(.+\.test\.ts|.+\.spec\.ts)\s*\((\d+)\s+test/i;
1842
- const lines = output.split("\n");
1843
1924
  for (const line of lines) {
1844
1925
  const match = line.match(suiteRegex);
1845
1926
  if (match) {
1846
1927
  const file = match[1];
1847
- const testCount = parseInt(match[2], 10);
1928
+ const testCount = parseInt(match[4], 10);
1848
1929
  const isPassed = line.includes("\u2713");
1849
1930
  if (isPassed) totalPassed += testCount;
1850
1931
  else totalFailed += testCount;
@@ -1864,15 +1945,39 @@ function parseVitestTextOutput(output, hasError) {
1864
1945
  });
1865
1946
  }
1866
1947
  }
1948
+ if (suites.length === 0) {
1949
+ const summaryMatch = output.match(/Tests\s+(\d+)\s+(passed|failed)/i);
1950
+ if (summaryMatch) {
1951
+ const count = parseInt(summaryMatch[1], 10);
1952
+ const status = summaryMatch[2].toLowerCase() === "passed" ? "passed" : "failed";
1953
+ suites.push({
1954
+ name: "Vitest Summary",
1955
+ file: "unknown",
1956
+ type: "unit",
1957
+ status,
1958
+ duration: 0,
1959
+ tests: Array.from({ length: count }, (_, i) => ({
1960
+ name: `test ${i + 1}`,
1961
+ file: "unknown",
1962
+ status,
1963
+ duration: 0,
1964
+ retries: 0
1965
+ }))
1966
+ });
1967
+ }
1968
+ }
1969
+ debug("vitest-text", `\u89E3\u6790\u5230 ${suites.length} \u4E2A\u5957\u4EF6, ${totalPassed} \u901A\u8FC7, ${totalFailed} \u5931\u8D25`);
1867
1970
  return {
1868
1971
  success: !hasError || totalFailed === 0,
1869
1972
  suites
1870
1973
  };
1871
1974
  }
1872
1975
  function mapVitestStatus(status) {
1976
+ if (!status) return "pending";
1873
1977
  switch (status) {
1874
1978
  case "passed":
1875
1979
  case "pass":
1980
+ case "done":
1876
1981
  return "passed";
1877
1982
  case "failed":
1878
1983
  case "fail":
@@ -1880,6 +1985,7 @@ function mapVitestStatus(status) {
1880
1985
  case "skipped":
1881
1986
  case "skip":
1882
1987
  case "pending":
1988
+ case "todo":
1883
1989
  return "skipped";
1884
1990
  default:
1885
1991
  return "pending";
@@ -2816,7 +2922,7 @@ async function testAIConnection(config) {
2816
2922
  }
2817
2923
 
2818
2924
  // src/services/mock-server.ts
2819
- import fs6 from "fs";
2925
+ import fs7 from "fs";
2820
2926
  import path7 from "path";
2821
2927
  var serverState = {
2822
2928
  running: false,
@@ -2829,18 +2935,18 @@ function getMockServerState() {
2829
2935
  }
2830
2936
  async function loadMockRoutes(routesDir) {
2831
2937
  const absDir = path7.resolve(process.cwd(), routesDir);
2832
- if (!fs6.existsSync(absDir)) {
2938
+ if (!fs7.existsSync(absDir)) {
2833
2939
  return [];
2834
2940
  }
2835
2941
  const routes = [];
2836
- const entries = fs6.readdirSync(absDir, { withFileTypes: true });
2942
+ const entries = fs7.readdirSync(absDir, { withFileTypes: true });
2837
2943
  for (const entry of entries) {
2838
2944
  if (!entry.isFile()) continue;
2839
2945
  const filePath = path7.join(absDir, entry.name);
2840
2946
  const ext = path7.extname(entry.name);
2841
2947
  try {
2842
2948
  if (ext === ".json") {
2843
- const content = fs6.readFileSync(filePath, "utf-8");
2949
+ const content = fs7.readFileSync(filePath, "utf-8");
2844
2950
  const parsed = JSON.parse(content);
2845
2951
  if (Array.isArray(parsed)) {
2846
2952
  routes.push(...parsed);
@@ -3032,11 +3138,11 @@ function generateMockRouteTemplate(name) {
3032
3138
  }
3033
3139
  function initMockRoutesDir(routesDir) {
3034
3140
  const absDir = path7.resolve(process.cwd(), routesDir);
3035
- if (!fs6.existsSync(absDir)) {
3036
- fs6.mkdirSync(absDir, { recursive: true });
3141
+ if (!fs7.existsSync(absDir)) {
3142
+ fs7.mkdirSync(absDir, { recursive: true });
3037
3143
  }
3038
3144
  const examplePath = path7.join(absDir, "example.json");
3039
- if (!fs6.existsSync(examplePath)) {
3145
+ if (!fs7.existsSync(examplePath)) {
3040
3146
  const exampleRoutes = [
3041
3147
  {
3042
3148
  method: "GET",
@@ -3060,24 +3166,24 @@ function initMockRoutesDir(routesDir) {
3060
3166
  }
3061
3167
  }
3062
3168
  ];
3063
- fs6.writeFileSync(examplePath, JSON.stringify(exampleRoutes, null, 2), "utf-8");
3169
+ fs7.writeFileSync(examplePath, JSON.stringify(exampleRoutes, null, 2), "utf-8");
3064
3170
  }
3065
3171
  }
3066
3172
 
3067
3173
  // src/services/visual.ts
3068
- import fs7 from "fs";
3174
+ import fs8 from "fs";
3069
3175
  import path8 from "path";
3070
3176
  import pixelmatch from "pixelmatch";
3071
3177
  import { PNG } from "pngjs";
3072
3178
  function compareImages(baselinePath, currentPath, diffOutputPath, threshold = 0.1) {
3073
- if (!fs7.existsSync(baselinePath)) {
3179
+ if (!fs8.existsSync(baselinePath)) {
3074
3180
  throw new Error(`\u57FA\u7EBF\u56FE\u7247\u4E0D\u5B58\u5728: ${baselinePath}`);
3075
3181
  }
3076
- if (!fs7.existsSync(currentPath)) {
3182
+ if (!fs8.existsSync(currentPath)) {
3077
3183
  throw new Error(`\u5F53\u524D\u56FE\u7247\u4E0D\u5B58\u5728: ${currentPath}`);
3078
3184
  }
3079
- const baseline = PNG.sync.read(fs7.readFileSync(baselinePath));
3080
- const current = PNG.sync.read(fs7.readFileSync(currentPath));
3185
+ const baseline = PNG.sync.read(fs8.readFileSync(baselinePath));
3186
+ const current = PNG.sync.read(fs8.readFileSync(currentPath));
3081
3187
  if (baseline.width !== current.width || baseline.height !== current.height) {
3082
3188
  return {
3083
3189
  passed: false,
@@ -3106,10 +3212,10 @@ function compareImages(baselinePath, currentPath, diffOutputPath, threshold = 0.
3106
3212
  let diffPath;
3107
3213
  if (diffPixels > 0) {
3108
3214
  const diffDir = path8.dirname(diffOutputPath);
3109
- if (!fs7.existsSync(diffDir)) {
3110
- fs7.mkdirSync(diffDir, { recursive: true });
3215
+ if (!fs8.existsSync(diffDir)) {
3216
+ fs8.mkdirSync(diffDir, { recursive: true });
3111
3217
  }
3112
- fs7.writeFileSync(diffOutputPath, PNG.sync.write(diff));
3218
+ fs8.writeFileSync(diffOutputPath, PNG.sync.write(diff));
3113
3219
  diffPath = diffOutputPath;
3114
3220
  }
3115
3221
  return {
@@ -3123,14 +3229,14 @@ function compareImages(baselinePath, currentPath, diffOutputPath, threshold = 0.
3123
3229
  };
3124
3230
  }
3125
3231
  function createBaseline(currentPath, baselinePath) {
3126
- if (!fs7.existsSync(currentPath)) {
3232
+ if (!fs8.existsSync(currentPath)) {
3127
3233
  throw new Error(`\u5F53\u524D\u622A\u56FE\u4E0D\u5B58\u5728: ${currentPath}`);
3128
3234
  }
3129
3235
  const baselineDir = path8.dirname(baselinePath);
3130
- if (!fs7.existsSync(baselineDir)) {
3131
- fs7.mkdirSync(baselineDir, { recursive: true });
3236
+ if (!fs8.existsSync(baselineDir)) {
3237
+ fs8.mkdirSync(baselineDir, { recursive: true });
3132
3238
  }
3133
- fs7.copyFileSync(currentPath, baselinePath);
3239
+ fs8.copyFileSync(currentPath, baselinePath);
3134
3240
  return baselinePath;
3135
3241
  }
3136
3242
  function updateBaseline(currentPath, baselinePath) {
@@ -3138,69 +3244,69 @@ function updateBaseline(currentPath, baselinePath) {
3138
3244
  }
3139
3245
  function updateAllBaselines(currentDir, baselineDir) {
3140
3246
  const updated = [];
3141
- if (!fs7.existsSync(currentDir)) {
3247
+ if (!fs8.existsSync(currentDir)) {
3142
3248
  return updated;
3143
3249
  }
3144
- const files = fs7.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
3250
+ const files = fs8.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
3145
3251
  for (const file of files) {
3146
3252
  const currentPath = path8.join(currentDir, file);
3147
3253
  const baselinePath = path8.join(baselineDir, file);
3148
3254
  const baselineDirAbs = path8.dirname(baselinePath);
3149
- if (!fs7.existsSync(baselineDirAbs)) {
3150
- fs7.mkdirSync(baselineDirAbs, { recursive: true });
3255
+ if (!fs8.existsSync(baselineDirAbs)) {
3256
+ fs8.mkdirSync(baselineDirAbs, { recursive: true });
3151
3257
  }
3152
- fs7.copyFileSync(currentPath, baselinePath);
3258
+ fs8.copyFileSync(currentPath, baselinePath);
3153
3259
  updated.push(file);
3154
3260
  }
3155
3261
  return updated;
3156
3262
  }
3157
3263
  function cleanBaselines(baselineDir) {
3158
- if (!fs7.existsSync(baselineDir)) {
3264
+ if (!fs8.existsSync(baselineDir)) {
3159
3265
  return 0;
3160
3266
  }
3161
- const files = fs7.readdirSync(baselineDir).filter((f) => f.endsWith(".png"));
3267
+ const files = fs8.readdirSync(baselineDir).filter((f) => f.endsWith(".png"));
3162
3268
  let count = 0;
3163
3269
  for (const file of files) {
3164
- fs7.unlinkSync(path8.join(baselineDir, file));
3270
+ fs8.unlinkSync(path8.join(baselineDir, file));
3165
3271
  count++;
3166
3272
  }
3167
3273
  return count;
3168
3274
  }
3169
3275
  function cleanDiffs(diffDir) {
3170
- if (!fs7.existsSync(diffDir)) {
3276
+ if (!fs8.existsSync(diffDir)) {
3171
3277
  return 0;
3172
3278
  }
3173
- const files = fs7.readdirSync(diffDir).filter((f) => f.endsWith(".png"));
3279
+ const files = fs8.readdirSync(diffDir).filter((f) => f.endsWith(".png"));
3174
3280
  let count = 0;
3175
3281
  for (const file of files) {
3176
- fs7.unlinkSync(path8.join(diffDir, file));
3282
+ fs8.unlinkSync(path8.join(diffDir, file));
3177
3283
  count++;
3178
3284
  }
3179
3285
  return count;
3180
3286
  }
3181
3287
  function listBaselines(baselineDir) {
3182
- if (!fs7.existsSync(baselineDir)) {
3288
+ if (!fs8.existsSync(baselineDir)) {
3183
3289
  return [];
3184
3290
  }
3185
- return fs7.readdirSync(baselineDir).filter((f) => f.endsWith(".png")).sort();
3291
+ return fs8.readdirSync(baselineDir).filter((f) => f.endsWith(".png")).sort();
3186
3292
  }
3187
3293
  function listDiffs(diffDir) {
3188
- if (!fs7.existsSync(diffDir)) {
3294
+ if (!fs8.existsSync(diffDir)) {
3189
3295
  return [];
3190
3296
  }
3191
- return fs7.readdirSync(diffDir).filter((f) => f.endsWith(".png")).sort();
3297
+ return fs8.readdirSync(diffDir).filter((f) => f.endsWith(".png")).sort();
3192
3298
  }
3193
3299
  function compareDirectories(baselineDir, currentDir, diffDir, threshold = 0.1) {
3194
3300
  const results = [];
3195
- if (!fs7.existsSync(currentDir)) {
3301
+ if (!fs8.existsSync(currentDir)) {
3196
3302
  return results;
3197
3303
  }
3198
- const currentFiles = fs7.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
3304
+ const currentFiles = fs8.readdirSync(currentDir).filter((f) => f.endsWith(".png"));
3199
3305
  for (const file of currentFiles) {
3200
3306
  const currentPath = path8.join(currentDir, file);
3201
3307
  const baselinePath = path8.join(baselineDir, file);
3202
3308
  const diffPath = path8.join(diffDir, file);
3203
- if (!fs7.existsSync(baselinePath)) {
3309
+ if (!fs8.existsSync(baselinePath)) {
3204
3310
  createBaseline(currentPath, baselinePath);
3205
3311
  results.push({
3206
3312
  passed: true,
@@ -3232,14 +3338,14 @@ function compareDirectories(baselineDir, currentDir, diffDir, threshold = 0.1) {
3232
3338
  }
3233
3339
 
3234
3340
  // src/services/source-analyzer.ts
3235
- import fs8 from "fs";
3341
+ import fs9 from "fs";
3236
3342
  import path9 from "path";
3237
3343
  function analyzeFile(filePath) {
3238
3344
  const absolutePath = path9.resolve(process.cwd(), filePath);
3239
- if (!fs8.existsSync(absolutePath)) {
3345
+ if (!fs9.existsSync(absolutePath)) {
3240
3346
  return { filePath, exports: [], apiCalls: [] };
3241
3347
  }
3242
- const content = fs8.readFileSync(absolutePath, "utf-8");
3348
+ const content = fs9.readFileSync(absolutePath, "utf-8");
3243
3349
  const ext = path9.extname(filePath);
3244
3350
  const result = {
3245
3351
  filePath,
@@ -3594,13 +3700,13 @@ function cleanTemplateUrl(url) {
3594
3700
  }
3595
3701
  function scanAPICalls(srcDir) {
3596
3702
  const absDir = path9.resolve(process.cwd(), srcDir);
3597
- if (!fs8.existsSync(absDir)) {
3703
+ if (!fs9.existsSync(absDir)) {
3598
3704
  return [];
3599
3705
  }
3600
3706
  const allCalls = [];
3601
3707
  const seen = /* @__PURE__ */ new Set();
3602
3708
  function walk(dir) {
3603
- const entries = fs8.readdirSync(dir, { withFileTypes: true });
3709
+ const entries = fs9.readdirSync(dir, { withFileTypes: true });
3604
3710
  for (const entry of entries) {
3605
3711
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist") continue;
3606
3712
  const fullPath = path9.join(dir, entry.name);
@@ -3608,7 +3714,7 @@ function scanAPICalls(srcDir) {
3608
3714
  walk(fullPath);
3609
3715
  } else if (entry.isFile() && /\.(ts|js|vue|mjs)$/.test(entry.name)) {
3610
3716
  try {
3611
- const content = fs8.readFileSync(fullPath, "utf-8");
3717
+ const content = fs9.readFileSync(fullPath, "utf-8");
3612
3718
  const calls = extractAPICalls(content, path9.relative(process.cwd(), fullPath));
3613
3719
  for (const call of calls) {
3614
3720
  const key = `${call.method}:${call.url}`;