qat-cli 0.3.3 → 0.3.5
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/README.md +1 -1
- package/dist/cli.js +744 -552
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +414 -144
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -3
- package/dist/index.d.ts +48 -3
- package/dist/index.js +414 -144
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2616,6 +2616,15 @@ var NoopAIProvider = class {
|
|
|
2616
2616
|
};
|
|
2617
2617
|
|
|
2618
2618
|
// src/ai/openai-provider.ts
|
|
2619
|
+
var import_chalk2 = __toESM(require("chalk"), 1);
|
|
2620
|
+
function isDebug() {
|
|
2621
|
+
return process.env.QAT_DEBUG === "true";
|
|
2622
|
+
}
|
|
2623
|
+
function debugLog(tag, ...args) {
|
|
2624
|
+
if (!isDebug()) return;
|
|
2625
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(11, 19);
|
|
2626
|
+
console.error(import_chalk2.default.gray(`[DEBUG ${timestamp}] [${tag}]`), ...args);
|
|
2627
|
+
}
|
|
2619
2628
|
var OpenAICompatibleProvider = class {
|
|
2620
2629
|
constructor(config) {
|
|
2621
2630
|
this.capabilities = {
|
|
@@ -2629,25 +2638,20 @@ var OpenAICompatibleProvider = class {
|
|
|
2629
2638
|
this.baseUrl = config.baseUrl || this.getDefaultBaseUrl(config.provider);
|
|
2630
2639
|
}
|
|
2631
2640
|
async generateTest(req) {
|
|
2641
|
+
debugLog("GENERATE", `type=${req.type} target=${req.target}`);
|
|
2632
2642
|
const systemPrompt = this.buildGenerateTestSystemPrompt(req);
|
|
2633
2643
|
const userPrompt = this.buildGenerateTestUserPrompt(req);
|
|
2634
2644
|
const content = await this.chat(systemPrompt, userPrompt);
|
|
2635
|
-
|
|
2645
|
+
const result = this.parseGenerateTestResponse(content);
|
|
2646
|
+
debugLog("GENERATE", `done code=${result.code.length}chars confidence=${result.confidence}`);
|
|
2647
|
+
return result;
|
|
2636
2648
|
}
|
|
2637
2649
|
async analyzeResult(req) {
|
|
2638
|
-
const systemPrompt = `\
|
|
2639
|
-
\u8F93\u51FA\
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
const
|
|
2643
|
-
const failed = r.suites.flatMap((s) => s.tests.filter((t) => t.status === "failed"));
|
|
2644
|
-
return `\u7C7B\u578B: ${r.type}, \u72B6\u6001: ${r.status}, \u8017\u65F6: ${r.duration}ms, \u5931\u8D25\u7528\u4F8B: ${failed.length}`;
|
|
2645
|
-
}).join("\n");
|
|
2646
|
-
const errorDetails = req.errorLogs?.join("\n") || req.testResults.flatMap((r) => r.suites.flatMap((s) => s.tests.filter((t) => t.status === "failed" && t.error))).map((t) => `[${t.name}] ${t.error?.message}`).join("\n") || "\u65E0\u9519\u8BEF\u8BE6\u60C5";
|
|
2647
|
-
const userPrompt = `\u6D4B\u8BD5\u7ED3\u679C:
|
|
2648
|
-
${resultSummary}
|
|
2649
|
-
|
|
2650
|
-
\u9519\u8BEF\u8BE6\u60C5:
|
|
2650
|
+
const systemPrompt = `\u6D4B\u8BD5\u5206\u6790\u4E13\u5BB6\u3002\u627E\u95EE\u9898\u6839\u56E0\uFF0C\u7ED9\u53EF\u64CD\u4F5C\u5EFA\u8BAE\u3002
|
|
2651
|
+
\u8F93\u51FA:1.\u6458\u8981(1-3\u53E5) 2.\u5EFA\u8BAE\u5217\u8868`;
|
|
2652
|
+
const failed = req.testResults.flatMap((r) => r.suites.flatMap((s) => s.tests.filter((t) => t.status === "failed")));
|
|
2653
|
+
const errorDetails = req.errorLogs?.join("\n") || failed.map((t) => `[${t.name}] ${t.error?.message}`).join("\n") || "\u65E0";
|
|
2654
|
+
const userPrompt = `\u5931\u8D25:${failed.length}
|
|
2651
2655
|
${errorDetails}`;
|
|
2652
2656
|
const content = await this.chat(systemPrompt, userPrompt);
|
|
2653
2657
|
return {
|
|
@@ -2657,23 +2661,22 @@ ${errorDetails}`;
|
|
|
2657
2661
|
};
|
|
2658
2662
|
}
|
|
2659
2663
|
async suggestFix(error) {
|
|
2660
|
-
const systemPrompt = `\
|
|
2661
|
-
\
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
const userPrompt = `\u9519\u8BEF\u4FE1\u606F: ${error.message}
|
|
2666
|
-
${error.stack ? `\u5806\u6808: ${error.stack}` : ""}
|
|
2667
|
-
${error.expected ? `\u671F\u671B\u503C: ${error.expected}` : ""}
|
|
2668
|
-
${error.actual ? `\u5B9E\u9645\u503C: ${error.actual}` : ""}`;
|
|
2664
|
+
const systemPrompt = `\u4EE3\u7801\u4FEE\u590D\u4E13\u5BB6\u3002\u7ED9\u51FA:1.\u95EE\u9898\u5B9A\u4F4D 2.\u4FEE\u590D\u65B9\u6848 3.\u793A\u4F8B\u4EE3\u7801`;
|
|
2665
|
+
const userPrompt = `\u9519\u8BEF:${error.message}${error.stack ? `
|
|
2666
|
+
\u5806\u6808:${error.stack}` : ""}${error.expected ? `
|
|
2667
|
+
\u671F\u671B:${error.expected}` : ""}${error.actual ? `
|
|
2668
|
+
\u5B9E\u9645:${error.actual}` : ""}`;
|
|
2669
2669
|
const content = await this.chat(systemPrompt, userPrompt);
|
|
2670
2670
|
return content.split("\n").filter((l) => l.trim().startsWith("-") || l.trim().startsWith("\u2022") || l.trim().match(/^\d+\./)).map((l) => l.replace(/^[-•\d.]+\s*/, "").trim()).filter(Boolean);
|
|
2671
2671
|
}
|
|
2672
2672
|
async reviewTest(req) {
|
|
2673
|
+
debugLog("REVIEW", `target=${req.target} type=${req.testType}`);
|
|
2673
2674
|
const systemPrompt = this.buildReviewTestSystemPrompt(req);
|
|
2674
2675
|
const userPrompt = this.buildReviewTestUserPrompt(req);
|
|
2675
2676
|
const content = await this.chat(systemPrompt, userPrompt);
|
|
2676
|
-
|
|
2677
|
+
const result = this.parseReviewTestResponse(content);
|
|
2678
|
+
debugLog("REVIEW", `approved=${result.approved} score=${result.score} feedback=${result.feedback}`);
|
|
2679
|
+
return result;
|
|
2677
2680
|
}
|
|
2678
2681
|
// ─── 内部方法 ──────────────────────────────────────────────
|
|
2679
2682
|
/**
|
|
@@ -2737,8 +2740,9 @@ ${error.actual ? `\u5B9E\u9645\u503C: ${error.actual}` : ""}`;
|
|
|
2737
2740
|
return { ok: false, message: `\u8FDE\u63A5\u5931\u8D25: ${error instanceof Error ? error.message : String(error)}`, latencyMs };
|
|
2738
2741
|
}
|
|
2739
2742
|
}
|
|
2740
|
-
async chat(systemPrompt, userPrompt) {
|
|
2743
|
+
async chat(systemPrompt, userPrompt, retries = 2) {
|
|
2741
2744
|
const url = `${this.baseUrl}/chat/completions`;
|
|
2745
|
+
const useStream = isDebug();
|
|
2742
2746
|
const body = {
|
|
2743
2747
|
model: this.model,
|
|
2744
2748
|
messages: [
|
|
@@ -2748,101 +2752,202 @@ ${error.actual ? `\u5B9E\u9645\u503C: ${error.actual}` : ""}`;
|
|
|
2748
2752
|
temperature: 0.3,
|
|
2749
2753
|
max_tokens: 4096
|
|
2750
2754
|
};
|
|
2755
|
+
if (useStream) {
|
|
2756
|
+
body.stream = true;
|
|
2757
|
+
}
|
|
2751
2758
|
const headers = {
|
|
2752
2759
|
"Content-Type": "application/json"
|
|
2753
2760
|
};
|
|
2754
2761
|
if (this.apiKey) {
|
|
2755
2762
|
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
2756
2763
|
}
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2764
|
+
debugLog("REQUEST", `POST ${url}`);
|
|
2765
|
+
debugLog("REQUEST", `model=${this.model} stream=${useStream}`);
|
|
2766
|
+
debugLog("SYSTEM", systemPrompt.length > 500 ? `${systemPrompt.slice(0, 500)}...` : systemPrompt);
|
|
2767
|
+
debugLog("USER", userPrompt.length > 1e3 ? `${userPrompt.slice(0, 1e3)}...` : userPrompt);
|
|
2768
|
+
let lastError = null;
|
|
2769
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
2770
|
+
try {
|
|
2771
|
+
if (attempt > 0) {
|
|
2772
|
+
debugLog("RETRY", `\u7B2C${attempt}\u6B21\u91CD\u8BD5...`);
|
|
2773
|
+
}
|
|
2774
|
+
const response = await fetch(url, {
|
|
2775
|
+
method: "POST",
|
|
2776
|
+
headers,
|
|
2777
|
+
body: JSON.stringify(body),
|
|
2778
|
+
signal: AbortSignal.timeout(12e4)
|
|
2779
|
+
// 120s timeout
|
|
2780
|
+
});
|
|
2781
|
+
if (!response.ok) {
|
|
2782
|
+
const text = await response.text().catch(() => "");
|
|
2783
|
+
if ((response.status === 429 || response.status >= 500) && attempt < retries) {
|
|
2784
|
+
const delay = Math.min(1e3 * Math.pow(2, attempt), 8e3);
|
|
2785
|
+
debugLog("RETRY", `HTTP ${response.status}, ${delay}ms\u540E\u91CD\u8BD5`);
|
|
2786
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
2787
|
+
lastError = new Error(`AI API \u8BF7\u6C42\u5931\u8D25 (${response.status}): ${text.slice(0, 200)}`);
|
|
2788
|
+
continue;
|
|
2789
|
+
}
|
|
2790
|
+
throw new Error(`AI API \u8BF7\u6C42\u5931\u8D25 (${response.status}): ${text.slice(0, 500)}`);
|
|
2791
|
+
}
|
|
2792
|
+
if (useStream && response.body) {
|
|
2793
|
+
const content = await this.readStream(response.body);
|
|
2794
|
+
debugLog("RESPONSE", content.length > 500 ? `${content.slice(0, 500)}...` : content);
|
|
2795
|
+
return content;
|
|
2796
|
+
}
|
|
2797
|
+
const data = await response.json();
|
|
2798
|
+
if (!data.choices?.[0]?.message?.content) {
|
|
2799
|
+
throw new Error("AI API \u8FD4\u56DE\u7A7A\u54CD\u5E94");
|
|
2800
|
+
}
|
|
2801
|
+
debugLog("RESPONSE", `tokens: prompt=${data.usage?.prompt_tokens} completion=${data.usage?.completion_tokens} total=${data.usage?.total_tokens}`);
|
|
2802
|
+
debugLog("RESPONSE", data.choices[0].message.content.length > 500 ? `${data.choices[0].message.content.slice(0, 500)}...` : data.choices[0].message.content);
|
|
2803
|
+
return data.choices[0].message.content;
|
|
2804
|
+
} catch (error) {
|
|
2805
|
+
if (error instanceof Error && error.name === "TimeoutError" && attempt < retries) {
|
|
2806
|
+
debugLog("TIMEOUT", `\u7B2C${attempt}\u6B21\u8D85\u65F6\uFF0C\u91CD\u8BD5\u4E2D...`);
|
|
2807
|
+
lastError = error;
|
|
2808
|
+
continue;
|
|
2809
|
+
}
|
|
2810
|
+
throw error;
|
|
2811
|
+
}
|
|
2767
2812
|
}
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2813
|
+
throw lastError || new Error("AI API \u8BF7\u6C42\u5931\u8D25");
|
|
2814
|
+
}
|
|
2815
|
+
/**
|
|
2816
|
+
* 读取 SSE 流式响应,实时输出内容
|
|
2817
|
+
*/
|
|
2818
|
+
async readStream(body) {
|
|
2819
|
+
const chunks = [];
|
|
2820
|
+
const decoder = new TextDecoder();
|
|
2821
|
+
const reader = body.getReader();
|
|
2822
|
+
let buffer = "";
|
|
2823
|
+
let lineCount = 0;
|
|
2824
|
+
try {
|
|
2825
|
+
while (true) {
|
|
2826
|
+
const { done, value } = await reader.read();
|
|
2827
|
+
if (done) break;
|
|
2828
|
+
buffer += decoder.decode(value, { stream: true });
|
|
2829
|
+
const lines = buffer.split("\n");
|
|
2830
|
+
buffer = lines.pop() || "";
|
|
2831
|
+
for (const line of lines) {
|
|
2832
|
+
const trimmed = line.trim();
|
|
2833
|
+
if (!trimmed || trimmed === "data: [DONE]") continue;
|
|
2834
|
+
if (!trimmed.startsWith("data: ")) continue;
|
|
2835
|
+
try {
|
|
2836
|
+
const json = JSON.parse(trimmed.slice(6));
|
|
2837
|
+
const delta = json.choices?.[0]?.delta?.content;
|
|
2838
|
+
if (delta) {
|
|
2839
|
+
chunks.push(delta);
|
|
2840
|
+
lineCount++;
|
|
2841
|
+
process.stderr.write(import_chalk2.default.gray(delta));
|
|
2842
|
+
if (lineCount % 20 === 0) {
|
|
2843
|
+
process.stderr.write("\n");
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
if (json.choices?.[0]?.finish_reason === "stop") {
|
|
2847
|
+
debugLog("STREAM", "\u5B8C\u6210");
|
|
2848
|
+
}
|
|
2849
|
+
} catch {
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
} finally {
|
|
2854
|
+
reader.releaseLock();
|
|
2855
|
+
}
|
|
2856
|
+
if (chunks.length > 0) {
|
|
2857
|
+
process.stderr.write("\n");
|
|
2858
|
+
}
|
|
2859
|
+
return chunks.join("");
|
|
2860
|
+
}
|
|
2861
|
+
/**
|
|
2862
|
+
* 压缩源码:保留签名和关键逻辑,剔除注释、空行、样式块
|
|
2863
|
+
* 目标:在保留准确性的前提下减少 token 消耗
|
|
2864
|
+
* @param code 源码内容
|
|
2865
|
+
* @param maxLength 最大长度
|
|
2866
|
+
* @param importPathRewrites import 路径重写映射(原路径→正确路径)
|
|
2867
|
+
*/
|
|
2868
|
+
compressSourceCode(code, maxLength = 3e3, importPathRewrites) {
|
|
2869
|
+
let compressed = code;
|
|
2870
|
+
if (importPathRewrites && importPathRewrites.size > 0) {
|
|
2871
|
+
compressed = this.rewriteImportPaths(compressed, importPathRewrites);
|
|
2771
2872
|
}
|
|
2772
|
-
|
|
2873
|
+
compressed = compressed.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "");
|
|
2874
|
+
compressed = compressed.replace(/<template[^>]*>([\s\S]*?)<\/template>/gi, (_match, content) => {
|
|
2875
|
+
return `<template>${content.replace(/\s*(?:class|style)\s*=\s*["'][^"']*["']/gi, "")}</template>`;
|
|
2876
|
+
});
|
|
2877
|
+
compressed = compressed.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
2878
|
+
compressed = compressed.replace(/(^|[^:])(\/\/.*$)/gm, "$1");
|
|
2879
|
+
compressed = compressed.replace(/\n\s*\n\s*\n/g, "\n\n");
|
|
2880
|
+
compressed = compressed.split("\n").map((line) => line.trimEnd()).join("\n").trim();
|
|
2881
|
+
if (compressed.length > maxLength) {
|
|
2882
|
+
const scriptMatch = compressed.match(/<script[^>]*>([\s\S]*?)<\/script>/i);
|
|
2883
|
+
const templateMatch = compressed.match(/<template[^>]*>([\s\S]*?)<\/template>/i);
|
|
2884
|
+
if (scriptMatch) {
|
|
2885
|
+
let scriptPart = scriptMatch[1].trim();
|
|
2886
|
+
scriptPart = compressFunctionBodies(scriptPart, maxLength * 0.7);
|
|
2887
|
+
const templatePart = templateMatch ? `<template>${templateMatch[1].replace(/\s+/g, " ").trim().slice(0, 300)}...</template>` : "";
|
|
2888
|
+
compressed = `${templatePart}
|
|
2889
|
+
<script${scriptMatch[0].match(/<script[^>]*>/)?.[0]?.slice(7) || ">"}>${scriptPart}</script>`;
|
|
2890
|
+
} else {
|
|
2891
|
+
compressed = compressFunctionBodies(compressed, maxLength);
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
return compressed;
|
|
2773
2895
|
}
|
|
2774
2896
|
buildGenerateTestSystemPrompt(req) {
|
|
2775
2897
|
const typeMap = {
|
|
2776
|
-
unit: "\u5355\u5143\u6D4B\u8BD5
|
|
2777
|
-
component: "\u7EC4\u4EF6\u6D4B\u8BD5
|
|
2778
|
-
e2e: "E2E\
|
|
2779
|
-
api: "API\
|
|
2780
|
-
visual: "\u89C6\u89C9\u56DE\u5F52\u6D4B\u8BD5
|
|
2781
|
-
performance: "\u6027\u80FD\u6D4B\u8BD5
|
|
2898
|
+
unit: "\u5355\u5143\u6D4B\u8BD5(Vitest)",
|
|
2899
|
+
component: "\u7EC4\u4EF6\u6D4B\u8BD5(Vitest+@vue/test-utils)",
|
|
2900
|
+
e2e: "E2E\u6D4B\u8BD5(Playwright)",
|
|
2901
|
+
api: "API\u6D4B\u8BD5(Vitest+fetch)",
|
|
2902
|
+
visual: "\u89C6\u89C9\u56DE\u5F52\u6D4B\u8BD5(Playwright)",
|
|
2903
|
+
performance: "\u6027\u80FD\u6D4B\u8BD5(Playwright)"
|
|
2782
2904
|
};
|
|
2783
|
-
return `\u4F60\u662F\
|
|
2784
|
-
\
|
|
2785
|
-
1. \u53EA\u8F93\u51FA\u6D4B\u8BD5\u4EE3\u7801\uFF0C\u4E0D\u8981\u591A\u4F59\u7684\u89E3\u91CA
|
|
2786
|
-
2. \u4EE3\u7801\u5FC5\u987B\u53EF\u76F4\u63A5\u8FD0\u884C\uFF0C\u5305\u542B\u6240\u6709\u5FC5\u8981\u7684 import
|
|
2787
|
-
3. \u6D4B\u8BD5\u7528\u4F8B\u8986\u76D6\uFF1A\u6B63\u5E38\u8DEF\u5F84\u3001\u8FB9\u754C\u6761\u4EF6\u3001\u9519\u8BEF\u5904\u7406
|
|
2788
|
-
4. \u4F7F\u7528\u4E2D\u6587\u63CF\u8FF0 it/test \u5757\u540D\u79F0
|
|
2789
|
-
5. Vue \u7EC4\u4EF6\u6D4B\u8BD5\u4F7F\u7528 @vue/test-utils \u7684 mount
|
|
2790
|
-
6. \u5982\u679C\u6709 props/emits \u4FE1\u606F\uFF0C\u52A1\u5FC5\u9488\u5BF9\u6BCF\u4E2A prop \u548C emit \u751F\u6210\u6D4B\u8BD5`;
|
|
2905
|
+
return `\u4F60\u662F\u524D\u7AEF\u6D4B\u8BD5\u5DE5\u7A0B\u5E08\uFF0C\u7F16\u5199${typeMap[req.type] || req.type}\u3002
|
|
2906
|
+
\u89C4\u5219:1.\u53EA\u8F93\u51FA\u6D4B\u8BD5\u4EE3\u7801 2.\u5305\u542B\u6240\u6709import 3.\u8986\u76D6\u6B63\u5E38/\u8FB9\u754C/\u9519\u8BEF 4.it\u540D\u7528\u4E2D\u6587 5.Vue\u7528mount 6.\u5FC5\u6D4B\u6BCF\u4E2Aprop\u548Cemit`;
|
|
2791
2907
|
}
|
|
2792
2908
|
buildGenerateTestUserPrompt(req) {
|
|
2793
2909
|
const importPath = this.computeTestImportPath(req.type, req.target);
|
|
2794
|
-
let prompt = `\
|
|
2795
|
-
\
|
|
2796
|
-
\u6D4B\u8BD5\u6587\u4EF6\u5C06\u653E\u5728: ${this.getTestOutputDir(req.type)}/
|
|
2797
|
-
\u6B63\u786E\u7684 import \u8DEF\u5F84: ${importPath}
|
|
2798
|
-
|
|
2799
|
-
\u91CD\u8981\uFF1Aimport \u8BED\u53E5\u4E2D\u5FC5\u987B\u4F7F\u7528\u4E0A\u8FF0\u6B63\u786E\u7684\u76F8\u5BF9\u8DEF\u5F84 ${importPath}\uFF0C\u4E0D\u8981\u4F7F\u7528 ${req.target} \u6216\u5176\u4ED6\u8DEF\u5F84\uFF01
|
|
2910
|
+
let prompt = `\u4E3A${req.target}\u751F\u6210${req.type}\u6D4B\u8BD5\u3002
|
|
2911
|
+
\u3010\u5F3A\u5236\u3011import\u88AB\u6D4B\u6A21\u5757\u5FC5\u987B\u7528: ${importPath}
|
|
2800
2912
|
`;
|
|
2801
2913
|
if (req.analysis) {
|
|
2802
|
-
|
|
2914
|
+
const parts = [];
|
|
2803
2915
|
if (req.analysis.exports?.length > 0) {
|
|
2804
|
-
|
|
2805
|
-
${
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
return ` - ${asyncFlag}${e.name}${params} [${e.kind}]`;
|
|
2809
|
-
}).join("\n")}
|
|
2810
|
-
`;
|
|
2916
|
+
parts.push(`\u5BFC\u51FA:${req.analysis.exports.map((e) => {
|
|
2917
|
+
const p = e.params?.length ? `(${e.params.join(",")})` : "";
|
|
2918
|
+
return `${e.isAsync ? "async " : ""}${e.name}${p}[${e.kind}]`;
|
|
2919
|
+
}).join(",")}`);
|
|
2811
2920
|
}
|
|
2812
2921
|
if (req.analysis.props?.length) {
|
|
2813
|
-
|
|
2814
|
-
${req.analysis.props.map(
|
|
2815
|
-
(p) => ` - ${p.name}: ${p.type}${p.required ? " (\u5FC5\u586B)" : " (\u53EF\u9009)"}`
|
|
2816
|
-
).join("\n")}
|
|
2817
|
-
`;
|
|
2922
|
+
parts.push(`Props:${req.analysis.props.map((p) => `${p.name}:${p.type}${p.required ? "!" : "?"}`).join(",")}`);
|
|
2818
2923
|
}
|
|
2819
2924
|
if (req.analysis.emits?.length) {
|
|
2820
|
-
|
|
2821
|
-
${req.analysis.emits.map(
|
|
2822
|
-
(e) => ` - ${e.name}${e.params?.length ? `(${e.params.join(", ")})` : ""}`
|
|
2823
|
-
).join("\n")}
|
|
2824
|
-
`;
|
|
2925
|
+
parts.push(`Emits:${req.analysis.emits.map((e) => `${e.name}(${e.params?.join(",") || ""})`).join(",")}`);
|
|
2825
2926
|
}
|
|
2826
2927
|
if (req.analysis.methods?.length) {
|
|
2827
|
-
|
|
2828
|
-
`;
|
|
2928
|
+
parts.push(`Methods:${req.analysis.methods.join(",")}`);
|
|
2829
2929
|
}
|
|
2830
2930
|
if (req.analysis.computed?.length) {
|
|
2831
|
-
|
|
2832
|
-
|
|
2931
|
+
parts.push(`Computed:${req.analysis.computed.join(",")}`);
|
|
2932
|
+
}
|
|
2933
|
+
if (req.analysis.importSignatures?.length) {
|
|
2934
|
+
parts.push(`\u4F9D\u8D56\u7B7E\u540D:${req.analysis.importSignatures.map(
|
|
2935
|
+
(imp) => `${imp.source}{${Object.entries(imp.signatures).map(([k, v]) => `${k}:${v}`).join(",")}}`
|
|
2936
|
+
).join(";")}`);
|
|
2833
2937
|
}
|
|
2938
|
+
prompt += parts.join("\n") + "\n";
|
|
2834
2939
|
}
|
|
2835
2940
|
if (req.context) {
|
|
2941
|
+
const importPathRewrites = this.buildImportPathRewrites(req.type, req.target);
|
|
2836
2942
|
prompt += `
|
|
2837
|
-
\u6E90\u7801
|
|
2838
|
-
\`\`\`
|
|
2839
|
-
${req.context}
|
|
2943
|
+
\u6E90\u7801:
|
|
2944
|
+
\`\`\`
|
|
2945
|
+
${this.compressSourceCode(req.context, 3e3, importPathRewrites)}
|
|
2840
2946
|
\`\`\`
|
|
2841
2947
|
`;
|
|
2842
2948
|
}
|
|
2843
2949
|
if (req.framework) {
|
|
2844
|
-
prompt +=
|
|
2845
|
-
\u6846\u67B6: ${req.framework}`;
|
|
2950
|
+
prompt += `\u6846\u67B6:${req.framework}`;
|
|
2846
2951
|
}
|
|
2847
2952
|
return prompt;
|
|
2848
2953
|
}
|
|
@@ -2873,18 +2978,54 @@ ${req.context}
|
|
|
2873
2978
|
return `${prefix}${cleanPath}`;
|
|
2874
2979
|
}
|
|
2875
2980
|
/**
|
|
2876
|
-
*
|
|
2981
|
+
* 构建 import 路径重写映射
|
|
2982
|
+
* 将源码中可能引用自身的各种写法,映射到测试文件中正确的导入路径
|
|
2877
2983
|
*/
|
|
2878
|
-
|
|
2879
|
-
const
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2984
|
+
buildImportPathRewrites(testType, targetPath) {
|
|
2985
|
+
const rewrites = /* @__PURE__ */ new Map();
|
|
2986
|
+
if (!targetPath) return rewrites;
|
|
2987
|
+
const correctImportPath = this.computeTestImportPath(testType, targetPath);
|
|
2988
|
+
const variations = /* @__PURE__ */ new Set();
|
|
2989
|
+
variations.add(targetPath);
|
|
2990
|
+
variations.add(targetPath.replace(/^\.\//, ""));
|
|
2991
|
+
const withoutExt = targetPath.replace(/\.(ts|js|tsx|jsx)$/, "");
|
|
2992
|
+
variations.add(withoutExt);
|
|
2993
|
+
const srcDirMatch = targetPath.match(/^(?:\.\/)?(src\/.+)$/);
|
|
2994
|
+
if (srcDirMatch) {
|
|
2995
|
+
variations.add(`@/${srcDirMatch[1]}`);
|
|
2996
|
+
variations.add(`@/${srcDirMatch[1].replace(/\.(ts|js|tsx|jsx)$/, "")}`);
|
|
2997
|
+
}
|
|
2998
|
+
const pathParts = targetPath.replace(/^\.\//, "").split("/");
|
|
2999
|
+
const fileName = pathParts[pathParts.length - 1];
|
|
3000
|
+
const fileNameNoExt = fileName.replace(/\.(ts|js|tsx|jsx|vue)$/, "");
|
|
3001
|
+
variations.add(`./${fileName}`);
|
|
3002
|
+
variations.add(`./${fileNameNoExt}`);
|
|
3003
|
+
for (let i = 1; i < pathParts.length; i++) {
|
|
3004
|
+
const relPath = "../".repeat(i) + pathParts.slice(i).join("/");
|
|
3005
|
+
variations.add(relPath);
|
|
3006
|
+
variations.add(relPath.replace(/\.(ts|js|tsx|jsx)$/, ""));
|
|
3007
|
+
}
|
|
3008
|
+
for (const variant of variations) {
|
|
3009
|
+
if (variant && variant !== correctImportPath) {
|
|
3010
|
+
rewrites.set(variant, correctImportPath);
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
return rewrites;
|
|
3014
|
+
}
|
|
3015
|
+
/**
|
|
3016
|
+
* 重写源码中的 import 路径
|
|
3017
|
+
* 将 from 'oldPath' / from "oldPath" 替换为正确的路径
|
|
3018
|
+
*/
|
|
3019
|
+
rewriteImportPaths(code, rewrites) {
|
|
3020
|
+
let result = code;
|
|
3021
|
+
for (const [oldPath, newPath] of rewrites) {
|
|
3022
|
+
const escaped = oldPath.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3023
|
+
const singleQuoteRegex = new RegExp(`(from\\s+')${escaped}(')`, "g");
|
|
3024
|
+
const doubleQuoteRegex = new RegExp(`(from\\s+")${escaped}(")`, "g");
|
|
3025
|
+
result = result.replace(singleQuoteRegex, `$1${newPath}$2`);
|
|
3026
|
+
result = result.replace(doubleQuoteRegex, `$1${newPath}$2`);
|
|
3027
|
+
}
|
|
3028
|
+
return result;
|
|
2888
3029
|
}
|
|
2889
3030
|
parseGenerateTestResponse(content) {
|
|
2890
3031
|
const codeBlockMatch = content.match(/```(?:typescript|ts|javascript|js)?\s*\n([\s\S]*?)```/);
|
|
@@ -2897,69 +3038,56 @@ ${req.context}
|
|
|
2897
3038
|
};
|
|
2898
3039
|
}
|
|
2899
3040
|
buildReviewTestSystemPrompt(_req) {
|
|
2900
|
-
return `\u4F60\u662F\
|
|
2901
|
-
|
|
2902
|
-
\
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
\u8F93\u51FA\u683C\u5F0F\uFF08\u4E25\u683C\u9075\u5B88\uFF09\uFF1A
|
|
2910
|
-
APPROVED: true \u6216 false
|
|
2911
|
-
SCORE: 0.0 \u5230 1.0 \u4E4B\u95F4\u7684\u8BC4\u5206
|
|
2912
|
-
FEEDBACK: \u4E00\u53E5\u8BDD\u5BA1\u8BA1\u610F\u89C1
|
|
2913
|
-
ISSUES: \u95EE\u9898\u5217\u8868\uFF08\u6BCF\u884C\u4E00\u4E2A\uFF0C\u683C\u5F0F "- \u95EE\u9898\u63CF\u8FF0"\uFF09
|
|
2914
|
-
SUGGESTIONS: \u6539\u8FDB\u5EFA\u8BAE\u5217\u8868\uFF08\u6BCF\u884C\u4E00\u4E2A\uFF0C\u683C\u5F0F "- \u5EFA\u8BAE\u63CF\u8FF0"\uFF09`;
|
|
3041
|
+
return `\u4F60\u662F\u6D4B\u8BD5\u5BA1\u8BA1\u4E13\u5BB6\u3002\u5BA1\u67E5\u6D4B\u8BD5\u4EE3\u7801\u662F\u5426\u51C6\u786E\u3002
|
|
3042
|
+
\u6807\u51C6:1.\u7C7B\u578B\u5339\u914D 2.\u8986\u76D6\u6838\u5FC3\u5BFC\u51FA/props/emits 3.\u65AD\u8A00\u6709\u6548(\u975E\u6C38\u771F) 4.import\u6B63\u786E 5.\u53EF\u8FD0\u884C
|
|
3043
|
+
\u8F93\u51FA:
|
|
3044
|
+
APPROVED:true\u6216false
|
|
3045
|
+
SCORE:0.0-1.0
|
|
3046
|
+
FEEDBACK:\u4E00\u53E5\u8BDD
|
|
3047
|
+
ISSUES:- \u95EE\u9898(\u6BCF\u884C\u4E00\u4E2A)
|
|
3048
|
+
SUGGESTIONS:- \u5EFA\u8BAE(\u6BCF\u884C\u4E00\u4E2A)`;
|
|
2915
3049
|
}
|
|
2916
3050
|
buildReviewTestUserPrompt(req) {
|
|
2917
3051
|
const importPath = this.computeTestImportPath(req.testType, req.target);
|
|
2918
|
-
let prompt = `\
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
3052
|
+
let prompt = `\u5BA1\u67E5\u6D4B\u8BD5\u4EE3\u7801\u3002\u88AB\u6D4B:${req.target} \u7C7B\u578B:${req.testType}
|
|
3053
|
+
\u3010\u5F3A\u5236\u3011import\u88AB\u6D4B\u6A21\u5757\u5FC5\u987B\u7528: ${importPath}
|
|
3054
|
+
`;
|
|
3055
|
+
const importPathRewrites = this.buildImportPathRewrites(req.testType, req.target);
|
|
3056
|
+
prompt += `
|
|
3057
|
+
\u6E90\u7801:
|
|
3058
|
+
\`\`\`
|
|
3059
|
+
${this.compressSourceCode(req.sourceCode, 2e3, importPathRewrites)}
|
|
3060
|
+
\`\`\`
|
|
3061
|
+
`;
|
|
3062
|
+
prompt += `
|
|
3063
|
+
\u6D4B\u8BD5\u4EE3\u7801:
|
|
2927
3064
|
\`\`\`
|
|
2928
|
-
|
|
2929
|
-
--- \u751F\u6210\u7684\u6D4B\u8BD5\u4EE3\u7801 ---
|
|
2930
|
-
\`\`\`typescript
|
|
2931
3065
|
${req.testCode}
|
|
2932
3066
|
\`\`\``;
|
|
2933
3067
|
if (req.analysis) {
|
|
2934
|
-
|
|
3068
|
+
const parts = [];
|
|
2935
3069
|
if (req.analysis.exports?.length > 0) {
|
|
2936
|
-
|
|
2937
|
-
\u5BFC\u51FA\u9879:
|
|
2938
|
-
${req.analysis.exports.map((e) => {
|
|
2939
|
-
const params = e.params?.length ? `(${e.params.join(", ")})` : "";
|
|
2940
|
-
const asyncFlag = e.isAsync ? "async " : "";
|
|
2941
|
-
return ` - ${asyncFlag}${e.name}${params} [${e.kind}]`;
|
|
2942
|
-
}).join("\n")}`;
|
|
3070
|
+
parts.push(`\u5BFC\u51FA:${req.analysis.exports.map((e) => `${e.isAsync ? "async " : ""}${e.name}(${e.params?.join(",") || ""})[${e.kind}]`).join(",")}`);
|
|
2943
3071
|
}
|
|
2944
3072
|
if (req.analysis.props?.length) {
|
|
2945
|
-
|
|
2946
|
-
Props:
|
|
2947
|
-
${req.analysis.props.map(
|
|
2948
|
-
(p) => ` - ${p.name}: ${p.type}${p.required ? " (\u5FC5\u586B)" : " (\u53EF\u9009)"}`
|
|
2949
|
-
).join("\n")}`;
|
|
3073
|
+
parts.push(`Props:${req.analysis.props.map((p) => `${p.name}:${p.type}${p.required ? "!" : "?"}`).join(",")}`);
|
|
2950
3074
|
}
|
|
2951
3075
|
if (req.analysis.emits?.length) {
|
|
3076
|
+
parts.push(`Emits:${req.analysis.emits.map((e) => `${e.name}(${e.params?.join(",") || ""})`).join(",")}`);
|
|
3077
|
+
}
|
|
3078
|
+
if (req.analysis.importSignatures?.length) {
|
|
3079
|
+
parts.push(`\u4F9D\u8D56:${req.analysis.importSignatures.map(
|
|
3080
|
+
(imp) => `${imp.source}{${Object.entries(imp.signatures).map(([k, v]) => `${k}:${v}`).join(",")}}`
|
|
3081
|
+
).join(";")}`);
|
|
3082
|
+
}
|
|
3083
|
+
if (parts.length > 0) {
|
|
2952
3084
|
prompt += `
|
|
2953
|
-
|
|
2954
|
-
${req.analysis.emits.map(
|
|
2955
|
-
(e) => ` - ${e.name}${e.params?.length ? `(${e.params.join(", ")})` : ""}`
|
|
2956
|
-
).join("\n")}`;
|
|
3085
|
+
\u5206\u6790:${parts.join("|")}`;
|
|
2957
3086
|
}
|
|
2958
3087
|
}
|
|
2959
3088
|
if (req.generationDescription) {
|
|
2960
3089
|
prompt += `
|
|
2961
|
-
|
|
2962
|
-
\u751F\u6210\u8005\u8BF4\u660E: ${req.generationDescription}`;
|
|
3090
|
+
\u8BF4\u660E:${req.generationDescription}`;
|
|
2963
3091
|
}
|
|
2964
3092
|
return prompt;
|
|
2965
3093
|
}
|
|
@@ -3019,6 +3147,61 @@ ${req.analysis.emits.map(
|
|
|
3019
3147
|
return urlMap[provider] || "https://api.openai.com/v1";
|
|
3020
3148
|
}
|
|
3021
3149
|
};
|
|
3150
|
+
function compressFunctionBodies(code, maxLength) {
|
|
3151
|
+
const lines = code.split("\n");
|
|
3152
|
+
const result = [];
|
|
3153
|
+
let depth = 0;
|
|
3154
|
+
let fnDepth = 0;
|
|
3155
|
+
let inFunction = false;
|
|
3156
|
+
let braceBalance = 0;
|
|
3157
|
+
let capturedLines = 0;
|
|
3158
|
+
for (const line of lines) {
|
|
3159
|
+
const trimmed = line.trim();
|
|
3160
|
+
for (const ch of trimmed) {
|
|
3161
|
+
if (ch === "{") {
|
|
3162
|
+
braceBalance++;
|
|
3163
|
+
depth++;
|
|
3164
|
+
}
|
|
3165
|
+
if (ch === "}") {
|
|
3166
|
+
braceBalance--;
|
|
3167
|
+
depth = Math.max(0, depth - 1);
|
|
3168
|
+
}
|
|
3169
|
+
}
|
|
3170
|
+
const isFnSignature = /^(export\s+)?(async\s+)?function\s|=>\s*\{|=>\s*$/m.test(trimmed) || /^(const|let|var)\s+\w+\s*=\s*(async\s+)?(\([^)]*\)|[^=])\s*=>/.test(trimmed);
|
|
3171
|
+
if (isFnSignature && !inFunction) {
|
|
3172
|
+
inFunction = true;
|
|
3173
|
+
fnDepth = depth;
|
|
3174
|
+
result.push(line);
|
|
3175
|
+
capturedLines++;
|
|
3176
|
+
continue;
|
|
3177
|
+
}
|
|
3178
|
+
if (inFunction) {
|
|
3179
|
+
const isReturn = trimmed.startsWith("return ");
|
|
3180
|
+
const isBranch = /^(if|else|switch|case|try|catch|finally|for|while)/.test(trimmed);
|
|
3181
|
+
const isClosing = trimmed === "}" && depth <= fnDepth - 1;
|
|
3182
|
+
if (isClosing) {
|
|
3183
|
+
result.push(line);
|
|
3184
|
+
inFunction = false;
|
|
3185
|
+
capturedLines++;
|
|
3186
|
+
} else if (isReturn || isBranch) {
|
|
3187
|
+
result.push(trimmed.length > 120 ? `${trimmed.slice(0, 120)}...` : line);
|
|
3188
|
+
capturedLines++;
|
|
3189
|
+
} else if (trimmed.startsWith("//") || trimmed === "") {
|
|
3190
|
+
} else if (capturedLines < maxLength / 30) {
|
|
3191
|
+
result.push(trimmed.length > 100 ? `${trimmed.slice(0, 100)}...` : line);
|
|
3192
|
+
capturedLines++;
|
|
3193
|
+
}
|
|
3194
|
+
} else {
|
|
3195
|
+
result.push(line);
|
|
3196
|
+
capturedLines++;
|
|
3197
|
+
}
|
|
3198
|
+
if (result.join("\n").length > maxLength) {
|
|
3199
|
+
result.push("// ... (truncated)");
|
|
3200
|
+
break;
|
|
3201
|
+
}
|
|
3202
|
+
}
|
|
3203
|
+
return result.join("\n");
|
|
3204
|
+
}
|
|
3022
3205
|
|
|
3023
3206
|
// src/ai/provider.ts
|
|
3024
3207
|
var providerRegistry = /* @__PURE__ */ new Map();
|
|
@@ -3508,15 +3691,18 @@ var import_node_path10 = __toESM(require("path"), 1);
|
|
|
3508
3691
|
function analyzeFile(filePath) {
|
|
3509
3692
|
const absolutePath = import_node_path10.default.resolve(process.cwd(), filePath);
|
|
3510
3693
|
if (!import_node_fs9.default.existsSync(absolutePath)) {
|
|
3511
|
-
return { filePath, exports: [], apiCalls: [] };
|
|
3694
|
+
return { filePath, exports: [], imports: [], importSignatures: [], apiCalls: [] };
|
|
3512
3695
|
}
|
|
3513
3696
|
const content = import_node_fs9.default.readFileSync(absolutePath, "utf-8");
|
|
3514
3697
|
const ext = import_node_path10.default.extname(filePath);
|
|
3515
3698
|
const result = {
|
|
3516
3699
|
filePath,
|
|
3517
3700
|
exports: extractExports(content, ext),
|
|
3701
|
+
imports: extractImports(content),
|
|
3702
|
+
importSignatures: [],
|
|
3518
3703
|
apiCalls: extractAPICalls(content, filePath)
|
|
3519
3704
|
};
|
|
3705
|
+
result.importSignatures = analyzeImportSignatures(result.imports, import_node_path10.default.dirname(absolutePath));
|
|
3520
3706
|
if (ext === ".vue") {
|
|
3521
3707
|
result.vueAnalysis = analyzeVueComponent(content, import_node_path10.default.basename(filePath, ".vue"));
|
|
3522
3708
|
const scriptMatch = content.match(/<script[^>]*>([\s\S]*?)<\/script>/);
|
|
@@ -3939,6 +4125,90 @@ function generateMockRoutesFromAPICalls(apiCalls) {
|
|
|
3939
4125
|
}
|
|
3940
4126
|
return routes;
|
|
3941
4127
|
}
|
|
4128
|
+
function extractImports(content) {
|
|
4129
|
+
const imports = [];
|
|
4130
|
+
const namedImportRegex = /import\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/g;
|
|
4131
|
+
let match;
|
|
4132
|
+
while ((match = namedImportRegex.exec(content)) !== null) {
|
|
4133
|
+
const names = match[1].split(",").map((n) => {
|
|
4134
|
+
const parts = n.trim().split(/\s+as\s+/);
|
|
4135
|
+
return parts[0].trim();
|
|
4136
|
+
}).filter(Boolean);
|
|
4137
|
+
imports.push({ names, source: match[2], isDefault: false, isNamespace: false });
|
|
4138
|
+
}
|
|
4139
|
+
const defaultImportRegex = /import\s+(\w+)\s+from\s*['"]([^'"]+)['"]/g;
|
|
4140
|
+
while ((match = defaultImportRegex.exec(content)) !== null) {
|
|
4141
|
+
const fullLine = content.slice(Math.max(0, match.index - 5), match.index + match[0].length);
|
|
4142
|
+
if (fullLine.includes("{")) continue;
|
|
4143
|
+
imports.push({ names: [match[1]], source: match[2], isDefault: true, isNamespace: false });
|
|
4144
|
+
}
|
|
4145
|
+
const namespaceImportRegex = /import\s*\*\s*as\s+(\w+)\s*from\s*['"]([^'"]+)['"]/g;
|
|
4146
|
+
while ((match = namespaceImportRegex.exec(content)) !== null) {
|
|
4147
|
+
imports.push({ names: [match[1]], source: match[2], isDefault: false, isNamespace: true });
|
|
4148
|
+
}
|
|
4149
|
+
return imports;
|
|
4150
|
+
}
|
|
4151
|
+
function analyzeImportSignatures(imports, baseDir) {
|
|
4152
|
+
const signatures = [];
|
|
4153
|
+
for (const imp of imports) {
|
|
4154
|
+
if (!imp.source.startsWith(".") && !imp.source.startsWith("@/") && !imp.source.startsWith("~")) {
|
|
4155
|
+
continue;
|
|
4156
|
+
}
|
|
4157
|
+
const resolvedPath = resolveImportPath2(imp.source, baseDir);
|
|
4158
|
+
if (!resolvedPath || !import_node_fs9.default.existsSync(resolvedPath)) continue;
|
|
4159
|
+
try {
|
|
4160
|
+
const content = import_node_fs9.default.readFileSync(resolvedPath, "utf-8");
|
|
4161
|
+
const ext = import_node_path10.default.extname(resolvedPath);
|
|
4162
|
+
const exports2 = extractExports(content, ext);
|
|
4163
|
+
const sigMap = {};
|
|
4164
|
+
for (const name of imp.names) {
|
|
4165
|
+
const exp = exports2.find((e) => e.name === name);
|
|
4166
|
+
if (exp) {
|
|
4167
|
+
const params = exp.params.length > 0 ? `(${exp.params.join(", ")})` : "";
|
|
4168
|
+
const ret = exp.returnType ? `: ${exp.returnType}` : "";
|
|
4169
|
+
const async = exp.isAsync ? "async " : "";
|
|
4170
|
+
sigMap[name] = `${async}${exp.kind}${params}${ret}`;
|
|
4171
|
+
} else if (imp.isDefault) {
|
|
4172
|
+
const defaultExp = exports2.find((e) => e.kind === "default");
|
|
4173
|
+
if (defaultExp) {
|
|
4174
|
+
sigMap[name] = `default[${defaultExp.name || "anonymous"}]`;
|
|
4175
|
+
}
|
|
4176
|
+
} else if (imp.isNamespace) {
|
|
4177
|
+
sigMap[name] = `{${exports2.map((e) => e.name).join(", ")}}`;
|
|
4178
|
+
}
|
|
4179
|
+
}
|
|
4180
|
+
if (ext === ".vue") {
|
|
4181
|
+
const vueAnalysis = analyzeVueComponent(content, import_node_path10.default.basename(resolvedPath, ".vue"));
|
|
4182
|
+
if (vueAnalysis.props.length > 0) {
|
|
4183
|
+
sigMap["__props__"] = vueAnalysis.props.map((p) => `${p.name}:${p.type}${p.required ? "!" : "?"}`).join(",");
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
if (Object.keys(sigMap).length > 0) {
|
|
4187
|
+
signatures.push({ source: imp.source, signatures: sigMap });
|
|
4188
|
+
}
|
|
4189
|
+
} catch {
|
|
4190
|
+
}
|
|
4191
|
+
}
|
|
4192
|
+
return signatures;
|
|
4193
|
+
}
|
|
4194
|
+
function resolveImportPath2(importSource, baseDir) {
|
|
4195
|
+
let resolved;
|
|
4196
|
+
if (importSource.startsWith("@/") || importSource.startsWith("~")) {
|
|
4197
|
+
const relativePath = importSource.replace(/^[@~]\//, "src/");
|
|
4198
|
+
resolved = import_node_path10.default.resolve(process.cwd(), relativePath);
|
|
4199
|
+
} else if (importSource.startsWith(".")) {
|
|
4200
|
+
resolved = import_node_path10.default.resolve(baseDir, importSource);
|
|
4201
|
+
} else {
|
|
4202
|
+
return null;
|
|
4203
|
+
}
|
|
4204
|
+
const extensions = [".ts", ".tsx", ".js", ".jsx", ".vue", "/index.ts", "/index.js"];
|
|
4205
|
+
if (import_node_fs9.default.existsSync(resolved)) return resolved;
|
|
4206
|
+
for (const ext of extensions) {
|
|
4207
|
+
const withExt = resolved + ext;
|
|
4208
|
+
if (import_node_fs9.default.existsSync(withExt)) return withExt;
|
|
4209
|
+
}
|
|
4210
|
+
return null;
|
|
4211
|
+
}
|
|
3942
4212
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3943
4213
|
0 && (module.exports = {
|
|
3944
4214
|
AI_PRESET_PROVIDERS,
|