codn_ts
Version:
智能代码分析工具 - 支持语义搜索、调用链分析和代码结构可视化,对大模型/AI agent 友好
614 lines • 21.9 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.semanticSearch = semanticSearch;
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
const glob_1 = require("glob");
const os_utils_1 = require("./utils/os_utils");
const lsp_core_1 = require("./utils/lsp_core");
// 扩展的语义关键词映射(50+ 语义类别)
const SEMANTIC_KEYWORDS = {
// 认证相关
auth: [
"authentication",
"login",
"logout",
"password",
"token",
"jwt",
"oauth",
"session",
"signin",
"signout",
],
login: [
"authentication",
"auth",
"signin",
"signon",
"user",
"password",
"credentials",
"login",
"login",
],
register: [
"signup",
"registration",
"create",
"user",
"account",
"register",
"enroll",
],
logout: [
"signout",
"logout",
"logout",
"logout",
"logout",
"logout",
"logout",
],
// 数据处理
parse: [
"parse",
"parse",
"convert",
"transform",
"parse",
"parse",
"parse",
"parse",
"parse",
],
validate: [
"validation",
"check",
"verify",
"validate",
"sanitize",
"validate",
"validate",
],
format: [
"format",
"formatting",
"format",
"format",
"format",
"format",
"format",
],
transform: [
"transform",
"convert",
"parse",
"format",
"transform",
"transform",
],
// 网络相关
api: [
"api",
"endpoint",
"route",
"http",
"request",
"response",
"fetch",
"axios",
"rest",
],
http: [
"http",
"https",
"request",
"response",
"api",
"endpoint",
"http",
"http",
],
fetch: [
"fetch",
"request",
"http",
"api",
"get",
"post",
"put",
"delete",
"fetch",
],
request: ["request", "http", "api", "fetch", "axios", "request", "request"],
// 数据库相关
database: [
"db",
"database",
"query",
"sql",
"mongodb",
"mysql",
"postgres",
"database",
],
query: [
"query",
"database",
"sql",
"select",
"insert",
"update",
"delete",
"query",
],
save: [
"save",
"store",
"persist",
"database",
"insert",
"update",
"save",
"save",
],
find: ["find", "search", "query", "select", "lookup", "find", "find"],
// 文件操作
file: ["file", "fs", "read", "write", "upload", "download", "path", "file"],
read: ["read", "file", "fs", "load", "parse", "import", "read", "read"],
write: ["write", "file", "fs", "save", "export", "create", "write", "write"],
upload: ["upload", "file", "multipart", "form", "upload", "upload"],
// 错误处理
error: [
"error",
"exception",
"catch",
"try",
"throw",
"handle",
"error",
"error",
],
exception: ["exception", "error", "catch", "try", "throw", "exception"],
catch: ["catch", "try", "error", "exception", "handle", "catch"],
// 配置相关
config: ["config", "configuration", "settings", "options", "env", "config"],
settings: ["settings", "config", "options", "preferences", "settings"],
env: ["environment", "env", "config", "settings", "env"],
// 工具函数
util: ["util", "utility", "helper", "tool", "common", "utils", "util"],
helper: ["helper", "util", "utility", "assist", "support", "helper"],
common: ["common", "shared", "util", "helper", "common"],
// 测试相关
test: ["test", "spec", "unit", "integration", "mock", "stub", "test"],
mock: ["mock", "stub", "fake", "test", "simulate", "mock"],
spec: ["spec", "test", "specification", "spec"],
// 业务逻辑
user: ["user", "customer", "member", "account", "user"],
order: ["order", "purchase", "transaction", "order"],
payment: ["payment", "pay", "billing", "invoice", "payment"],
notification: ["notification", "alert", "message", "email", "sms"],
// 安全相关
security: ["security", "secure", "encrypt", "hash", "security"],
encrypt: ["encrypt", "encryption", "hash", "security", "encrypt"],
hash: ["hash", "encrypt", "password", "security", "hash"],
// 缓存相关
cache: ["cache", "caching", "redis", "memory", "cache"],
redis: ["redis", "cache", "memory", "redis"],
// 日志相关
log: ["log", "logging", "logger", "debug", "log"],
debug: ["debug", "log", "trace", "debug"],
// 时间相关
time: ["time", "date", "timestamp", "duration", "time"],
date: ["date", "time", "timestamp", "date"],
// 数学计算
calculate: ["calculate", "compute", "math", "sum", "calculate"],
sum: ["sum", "add", "calculate", "total", "sum"],
// 字符串处理
string: ["string", "text", "char", "string", "string"],
replace: ["replace", "substitute", "string", "replace"],
// 数组处理
array: ["array", "list", "collection", "array"],
filter: ["filter", "array", "list", "filter"],
map: ["map", "array", "transform", "map"],
reduce: ["reduce", "array", "aggregate", "reduce"],
// 对象处理
object: ["object", "obj", "entity", "object"],
merge: ["merge", "combine", "object", "merge"],
clone: ["clone", "copy", "duplicate", "clone"],
// 异步处理
async: ["async", "await", "promise", "async"],
promise: ["promise", "async", "await", "promise"],
await: ["await", "async", "promise", "await"],
};
// 代码复杂度评估
function calculateComplexity(content) {
let complexity = 1;
// 循环复杂度
const loops = (content.match(/\b(for|while|do)\b/g) || []).length;
complexity += loops * 2;
// 条件复杂度
const conditions = (content.match(/\b(if|else|switch|case)\b/g) || []).length;
complexity += conditions;
// 函数调用复杂度
const functionCalls = (content.match(/\w+\(/g) || []).length;
complexity += functionCalls * 0.5;
// 嵌套深度
const maxNesting = Math.max(...content.split("\n").map((line) => {
const match = line.match(/^\s*/);
const indent = match ? match[0].length : 0;
return Math.floor(indent / 2);
}));
complexity += maxNesting * 0.5;
return Math.min(10, complexity);
}
// 提取函数参数和返回值
function extractFunctionSignature(content, symbolName) {
const parameters = [];
let returnType = "";
// 匹配函数定义
const functionPatterns = [
// 普通函数
new RegExp(`function\\s+${escapeRegExp(symbolName)}\\s*\\(([^)]*)\\)\\s*:\\s*([^{\\s]+)?`, "i"),
// 箭头函数
new RegExp(`(?:const|let|var)\\s+${escapeRegExp(symbolName)}\\s*=\\s*(?:async\\s*)?\\(([^)]*)\\)\\s*=>\\s*([^{\\s]+)?`, "i"),
// 方法定义
new RegExp(`${escapeRegExp(symbolName)}\\s*\\(([^)]*)\\)\\s*:\\s*([^{\\s]+)?`, "i"),
];
for (const pattern of functionPatterns) {
const match = content.match(pattern);
if (match) {
// 提取参数
const paramString = match[1];
if (paramString.trim()) {
const params = paramString.split(",").map((p) => {
const param = p.trim();
// 提取参数名(去掉类型注解)
const nameMatch = param.match(/^([a-zA-Z_$][a-zA-Z0-9_$]*)/);
return nameMatch ? nameMatch[1] : param;
});
parameters.push(...params);
}
// 提取返回值类型
if (match[2]) {
returnType = match[2].trim();
}
break;
}
}
return { parameters, returnType };
}
// 分析调用关系
function analyzeCallRelationships(content, symbolName) {
const callers = [];
const callees = [];
const lines = content.split("\n");
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
// 查找调用当前函数的地方
const callerPattern = new RegExp(`\\b(\\w+)\\s*\\([^)]*\\)\\s*;?\\s*(?://.*)?$`, "g");
let callerMatch;
while ((callerMatch = callerPattern.exec(line)) !== null) {
const callerName = callerMatch[1];
if (callerName !== symbolName && !callees.includes(callerName)) {
callees.push(callerName);
}
}
// 查找当前函数调用的其他函数
const calleePattern = new RegExp(`\\b${escapeRegExp(symbolName)}\\s*\\([^)]*\\)`, "g");
if (calleePattern.test(line)) {
// 提取这一行中调用的函数
const functionCallPattern = /\b(\w+)\s*\(/g;
let functionMatch;
while ((functionMatch = functionCallPattern.exec(line)) !== null) {
const functionName = functionMatch[1];
if (functionName !== symbolName && !callers.includes(functionName)) {
callers.push(functionName);
}
}
}
}
return { callers, callees };
}
// 1. 精确匹配维度 (权重: 0.8)
function exactMatchScore(query, symbolName) {
const queryLower = query.toLowerCase();
const nameLower = symbolName.toLowerCase();
// 完全匹配
if (nameLower === queryLower)
return 1.0;
// 包含匹配
if (nameLower.includes(queryLower) || queryLower.includes(nameLower))
return 0.8;
// 驼峰命名匹配 (如 "userLogin" 匹配 "user login")
const camelCaseWords = nameLower.replace(/([A-Z])/g, " $1").toLowerCase();
if (camelCaseWords.includes(queryLower))
return 0.7;
// 下划线命名匹配
const underscoreWords = nameLower.replace(/_/g, " ");
if (underscoreWords.includes(queryLower))
return 0.6;
return 0.0;
}
// 2. 语义关键词匹配维度 (权重: 0.6)
function semanticKeywordScore(query, symbolName, description) {
const queryLower = query.toLowerCase();
const nameLower = symbolName.toLowerCase();
const descLower = description.toLowerCase();
let score = 0;
const queryWords = queryLower.split(/\s+/);
for (const word of queryWords) {
if (SEMANTIC_KEYWORDS[word]) {
const synonyms = SEMANTIC_KEYWORDS[word];
for (const synonym of synonyms) {
if (nameLower.includes(synonym) || descLower.includes(synonym)) {
score += 0.3;
}
}
}
}
return Math.min(1.0, score);
}
// 3. 上下文相关性维度 (权重: 0.4)
function contextRelevanceScore(query, parameters, returnType, comments) {
const queryLower = query.toLowerCase();
let score = 0;
// 3.1 函数参数分析 (权重: 0.4)
const paramScore = parameters.reduce((acc, param) => {
if (param.toLowerCase().includes(queryLower))
return acc + 0.5;
return acc;
}, 0);
score += Math.min(1.0, paramScore) * 0.4;
// 3.2 返回值分析 (权重: 0.3)
if (returnType && returnType.toLowerCase().includes(queryLower)) {
score += 0.3;
}
// 3.3 注释内容分析 (权重: 0.2)
if (comments && comments.toLowerCase().includes(queryLower)) {
score += 0.2;
}
// 3.4 代码上下文分析 (权重: 0.1)
const contextWords = queryLower.split(/\s+/);
for (const word of contextWords) {
if (word.length > 2 &&
(parameters.some((p) => p.toLowerCase().includes(word)) ||
(returnType && returnType.toLowerCase().includes(word)))) {
score += 0.1;
}
}
return Math.min(1.0, score);
}
// 4. 依赖关系相关性维度 (权重: 0.3)
function dependencyRelevanceScore(query, callers, callees) {
const queryLower = query.toLowerCase();
let score = 0;
// 4.1 调用者分析 (权重: 0.5)
const callerScore = callers.reduce((acc, caller) => {
if (caller.toLowerCase().includes(queryLower))
return acc + 0.4;
return acc;
}, 0);
score += Math.min(1.0, callerScore) * 0.5;
// 4.2 被调用者分析 (权重: 0.3)
const calleeScore = callees.reduce((acc, callee) => {
if (callee.toLowerCase().includes(queryLower))
return acc + 0.3;
return acc;
}, 0);
score += Math.min(1.0, calleeScore) * 0.3;
// 4.3 模块依赖分析 (权重: 0.2)
const allRelated = [...callers, ...callees];
const moduleScore = allRelated.reduce((acc, related) => {
if (related.toLowerCase().includes(queryLower))
return acc + 0.2;
return acc;
}, 0);
score += Math.min(1.0, moduleScore) * 0.2;
return Math.min(1.0, score);
}
// 5. 使用频率相关性维度 (权重: 0.2)
function usageRelevanceScore(complexity, callCount) {
let score = 0;
// 5.1 调用频率 (权重: 0.4)
const frequencyScore = callCount > 100
? 1.0
: callCount > 50
? 0.8
: callCount > 20
? 0.6
: callCount > 10
? 0.4
: callCount > 5
? 0.2
: 0.1;
score += frequencyScore * 0.4;
// 5.2 代码复杂度 (权重: 0.3)
const complexityScore = complexity > 8
? 1.0
: complexity > 6
? 0.8
: complexity > 4
? 0.6
: complexity > 2
? 0.4
: 0.2;
score += complexityScore * 0.3;
// 5.3 函数重要性 (权重: 0.2)
const importanceScore = callCount > 0 ? 0.8 : 0.2;
score += importanceScore * 0.2;
// 5.4 代码质量 (权重: 0.1)
const qualityScore = complexity < 5 ? 1.0 : complexity < 8 ? 0.6 : 0.3;
score += qualityScore * 0.1;
return score;
}
// 计算最终相关性分数
function calculateFinalRelevance(query, symbolName, description, parameters, returnType, callers, callees, complexity, callCount) {
const weights = {
exactMatch: 0.8,
semanticKeyword: 0.6,
context: 0.4,
dependency: 0.3,
usage: 0.2,
};
const scores = {
exactMatch: exactMatchScore(query, symbolName),
semanticKeyword: semanticKeywordScore(query, symbolName, description),
context: contextRelevanceScore(query, parameters, returnType, description),
dependency: dependencyRelevanceScore(query, callers, callees),
usage: usageRelevanceScore(complexity, callCount),
};
// 加权平均
let totalScore = 0;
let totalWeight = 0;
for (const [dimension, weight] of Object.entries(weights)) {
totalScore += scores[dimension] * weight;
totalWeight += weight;
}
return totalScore / totalWeight;
}
// 提取代码关键词
function extractCodeKeywords(content, symbolName) {
const keywords = [];
// 提取函数参数
const { parameters } = extractFunctionSignature(content, symbolName);
keywords.push(...parameters);
// 提取注释中的关键词
const commentPattern = /\/\*\*?([^*]|\*(?!\/))*\*\/|\/\/.*$/gm;
const comments = content.match(commentPattern) || [];
for (const comment of comments) {
const words = comment.replace(/[\/\*]/g, "").split(/\s+/);
keywords.push(...words.filter((w) => w.length > 3));
}
// 提取变量名和函数调用
const identifierPattern = /\b[a-zA-Z_][a-zA-Z0-9_]*\b/g;
const identifiers = content.match(identifierPattern) || [];
keywords.push(...identifiers.filter((id) => id.length > 2 && id !== symbolName));
return [...new Set(keywords)];
}
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
async function semanticSearch(query, projectRoot, options = {}) {
const { limit = 20, minRelevance = 0.1, includeComments = true, includeTests = false, } = options;
const results = [];
try {
const languages = (0, os_utils_1.detectDominantLanguages)(projectRoot, {
ignoredDirs: new Set(["node_modules", "dist"]),
topN: 1,
}) ?? [];
if (languages.length === 0) {
return results;
}
const lang = languages[0];
const file_ext = (0, os_utils_1.getLanguageFileExtensions)(lang);
const client = new lsp_core_1.LSPClient(`file://${projectRoot}`, {
...lsp_core_1.DEFAULT_CONFIG,
timeout: 30000,
logLevel: "error",
});
await client.start(lang);
try {
const files = (await (0, glob_1.glob)(`**/*.{${file_ext}}`, {
cwd: projectRoot,
ignore: includeTests
? "node_modules/**"
: ["node_modules/**", "**/*.test.*", "**/*.spec.*"],
absolute: true,
})) ?? [];
for (const filePath of files) {
const fileUri = `file://${filePath}`;
const relativePath = path.relative(projectRoot, filePath);
try {
const content = fs.readFileSync(filePath, "utf-8");
await client.sendDidOpen(fileUri, content, "typescript");
const symbols = await client.sendDocumentSymbol(fileUri);
if (!symbols)
continue;
for (const symbol of symbols) {
// 提取函数签名信息
const { parameters, returnType } = extractFunctionSignature(content, symbol.name);
// 分析调用关系
const { callers, callees } = analyzeCallRelationships(content, symbol.name);
// 计算代码复杂度
const complexity = calculateComplexity(content);
// 估算调用次数(基于函数名在代码中的出现次数)
const matches = content.match(new RegExp(`\\b${escapeRegExp(symbol.name)}\\s*\\(`, "g"));
const callCount = matches ? matches.length : 0;
// 计算相关性分数
const relevance = calculateFinalRelevance(query, symbol.name, symbol.detail || "", parameters, returnType, callers, callees, complexity, callCount);
if (relevance >= minRelevance) {
const keywords = extractCodeKeywords(content, symbol.name);
results.push({
type: "semantic",
name: symbol.name,
file: relativePath,
line: symbol.location.range.start.line + 1,
column: symbol.location.range.start.character + 1,
description: symbol.detail || undefined,
kind: symbol.kind,
relevance,
context: `Function with ${parameters.length} parameters${returnType ? `, returns ${returnType}` : ""}`,
keywords,
parameters,
returnType,
callers,
callees,
complexity,
callCount,
});
}
}
await client.sendDidClose(fileUri);
}
catch (err) {
// 忽略单个文件的错误
}
}
}
finally {
await client.shutdown();
}
// 按相关性排序
return results.sort((a, b) => b.relevance - a.relevance).slice(0, limit);
}
catch (error) {
console.error("语义搜索错误:", error);
return results;
}
}
//# sourceMappingURL=semantic_search.js.map