From 0756bf12d10cf1b7f78c571de0a9ad69cbaeb7ca Mon Sep 17 00:00:00 2001
From: curtis <curtis@i-mps.com>
Date: 星期一, 30 三月 2026 14:24:17 +0800
Subject: [PATCH] fix: 更新內部引用方法參照

---
 scripts/scanimpl_annalysis_addon_json.test.js |  183 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 183 insertions(+), 0 deletions(-)

diff --git a/scripts/scanimpl_annalysis_addon_json.test.js b/scripts/scanimpl_annalysis_addon_json.test.js
new file mode 100644
index 0000000..3492efb
--- /dev/null
+++ b/scripts/scanimpl_annalysis_addon_json.test.js
@@ -0,0 +1,183 @@
+const fs = require('fs');
+const path = require('path');
+
+const PROJECT_ROOT = path.resolve(__dirname, '..');
+const SOURCE_FILE = path.join(PROJECT_ROOT, 'CB_IMGPSScanImp.pas.bk');
+const JSON_DIR = path.join(PROJECT_ROOT, 'doc', 'curtis', 'prompt', 'scanimpl_analysis');
+const REVIEW_FILE = path.join(PROJECT_ROOT, 'CB_IMGPSScanImp_Remain_Review.pas');
+
+// --- 動態 Delphi 語法解析器 ---
+function findDelphiMethodBounds(lines, matcher, startIndexHint = 0) {
+    // 取得函式宣告的前半段特徵,並統一轉換為小寫比對 (避免 Delphi 的大小寫差異)
+    // 例如: "procedure TCB_IMGPSScanX.initkscan"
+    const rawSignature = matcher.split('(')[0].trim().toLowerCase().replace(';', '');
+    
+    // 針對有參數跟沒參數的,進一步過濾乾淨
+    const signature = rawSignature.split(':')[0].trim();
+
+    let startIdx = -1;
+    let endIdx = -1;
+
+    // 1. 找尋起點 (從 startIndexHint 開始找,支援屬性 getter/setter 重名問題)
+    for (let i = startIndexHint; i < lines.length; i++) {
+        const line = lines[i].toLowerCase();
+        
+        // 確保是宣告實作區段,而非 interface 宣告
+        if (line.includes(signature) && 
+           (line.startsWith('procedure ') || line.startsWith('function ') || line.includes(' procedure ') || line.includes(' function '))) {
+            
+            // 避免找到 interface 區段的宣告 (通常以分號結尾且無 begin)
+            // 簡單判斷:如果是實作區,往下找幾行應該會有 begin, var, const 等宣告
+            let isImpl = false;
+            for(let scan = i; scan < Math.min(i + 20, lines.length); scan++) {
+                if (lines[scan].toLowerCase().match(/\b(begin|var|const|type)\b/)) {
+                    isImpl = true;
+                    break;
+                }
+            }
+            if (isImpl) {
+                startIdx = i;
+                break;
+            }
+        }
+    }
+
+    if (startIdx === -1) return null;
+
+    // 2. 透過括號與 Begin/End 深度計算法找尋終點 end;
+    let openCount = 0;
+    let foundBegin = false;
+    let inAsm = false;
+
+    for (let i = startIdx; i < lines.length; i++) {
+        let line = lines[i].toLowerCase();
+        
+        // 剃除字串與註解,避免干擾括號計算
+        line = line.replace(/'[^']*'/g, '').replace(/\/\/.*$/, '').replace(/\{[^}]*\}/g, '').replace(/\(\*.*?\*\)/g, '');
+        
+        // 分割出乾淨的字詞
+        const words = line.split(/[\s;()\[\]=]+/g).filter(Boolean);
+
+        for (const word of words) {
+            if (word === 'asm') inAsm = true;
+            if (word === 'begin' || word === 'case' || word === 'try' || word === 'asm') {
+                openCount++;
+                foundBegin = true;
+            }
+            if (word === 'end') {
+                openCount--;
+                if (inAsm && openCount === 0) inAsm = false;
+            }
+        }
+
+        // 當發現了 begin 且深度歸零,代表這個方法完全結束了
+        if (foundBegin && openCount === 0) {
+            endIdx = i;
+            break;
+        }
+    }
+
+    return { lIndex: startIdx + 1, rIndex: endIdx + 1 };
+}
+
+function runTest() {
+    console.log("==================================================");
+    console.log("  CB_IMGPSScanImp 動態全域解析與拆解測試腳本 (自動校正行號)");
+    console.log("==================================================\n");
+
+    if (!fs.existsSync(SOURCE_FILE)) {
+        console.error(`[錯誤] 找不到來源備份檔: ${SOURCE_FILE}`);
+        return;
+    }
+
+    let sourceLines = fs.readFileSync(SOURCE_FILE, 'utf-8').split(/\r?\n/);
+    let parsedTargets = [];
+    let totalUpdated = 0;
+    let missingCount = 0;
+
+    if (!fs.existsSync(JSON_DIR)) {
+        console.error(`[錯誤] 找不到 JSON 目錄: ${JSON_DIR}`);
+        return;
+    }
+
+    const files = fs.readdirSync(JSON_DIR).filter(f => f.endsWith('.json'));
+    console.log(`>> 找到 ${files.length} 個 JSON 分類檔,開始進行語法比對與深度解析...`);
+
+    // 略過 interface 區段,避免把 interface 的宣告誤當作實作
+    let implementationStartLine = 0;
+    for(let i=0; i<sourceLines.length; i++){
+        if(sourceLines[i].toLowerCase().trim() === 'implementation') {
+            implementationStartLine = i;
+            break;
+        }
+    }
+
+    // --- 0.2.2.1: 測試與動態驗證 (Verification & Correction Phase) ---
+    for (const file of files) {
+        const filePath = path.join(JSON_DIR, file);
+        let hasChanges = false;
+        try {
+            const content = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
+            const items = Array.isArray(content) ? content : [content];
+            
+            for (let item of items) {
+                // 呼叫 AST 語法掃描器動態找尋真實行號 (從 implementation 之後開始找)
+                const actualBounds = findDelphiMethodBounds(sourceLines, item.matcher, implementationStartLine);
+                
+                if (actualBounds && actualBounds.lIndex > 0 && actualBounds.rIndex >= actualBounds.lIndex) {
+                    // 若偵測到的與原本不同的,自動更新並標記變更
+                    if (item.lIndex != actualBounds.lIndex || item.rIndex != actualBounds.rIndex) {
+                        item.lIndex = actualBounds.lIndex.toString();
+                        item.rIndex = actualBounds.rIndex.toString();
+                        hasChanges = true;
+                        totalUpdated++;
+                    }
+                    // 轉換為 0-based index 加入待刪除清單
+                    parsedTargets.push({ 
+                        ...item, 
+                        startIdx: actualBounds.lIndex - 1, 
+                        endIdx: actualBounds.rIndex - 1 
+                    });
+                } else {
+                    console.warn(`[警告] 無法在原始碼中定位 Matcher 或其包含無效範圍: ${item.matcher}`);
+                    missingCount++;
+                }
+            }
+
+            // 若有修正,回寫覆蓋原本的 JSON 檔
+            if (hasChanges) {
+                fs.writeFileSync(filePath, JSON.stringify(items, null, 2), 'utf-8');
+            }
+        } catch (e) {
+            console.error(`[錯誤] 解析 JSON 檔案 ${file} 失敗:`, e.message);
+        }
+    }
+
+    console.log(`\n>> 驗證完成。`);
+    console.log(`   成功動態定位: ${parsedTargets.length} 個區段。`);
+    console.log(`   自動校正誤差: ${totalUpdated} 個。`);
+    console.log(`   無法定位遺漏: ${missingCount} 個。\n`);
+
+    // --- 0.2.2.2: 執行區段移除並審核 (Removal Phase) ---
+    console.log("[階段 2] 執行區段移除...");
+    
+    // 依照 startIdx 由大到小排序 (由尾部往上刪),保證刪除時上方行號不會產生位移跑版
+    parsedTargets.sort((a, b) => b.startIdx - a.startIdx);
+
+    let removedCount = 0;
+    for (const target of parsedTargets) {
+        const deleteCount = target.endIdx - target.startIdx + 1;
+        if (deleteCount > 0) {
+            sourceLines.splice(target.startIdx, deleteCount);
+            removedCount++;
+        }
+    }
+
+    // 寫入完整剩餘結果至實體檔案
+    fs.writeFileSync(REVIEW_FILE, sourceLines.join('\n'), 'utf-8');
+    console.log(`✅ 成功移除 ${removedCount} 個方法區段。`);
+    console.log(`✅ 移除後的剩餘程式碼已儲存至: \n   ${REVIEW_FILE}`);
+    console.log(`   您可以開啟該檔案進行人工審核 (裡面應該只剩下全域變數與宣告區段)。`);
+}
+
+runTest();
\ No newline at end of file

--
Gitblit v1.8.0