autosnippet
Version:
Extract code patterns into a knowledge base for AI coding assistants
937 lines (936 loc) • 41.3 kB
JavaScript
/**
* LanguageExtensions — 语言检测与语言特有扩展字段构建
*
* 负责:
* - 文件扩展名 → 语言映射(委托 LanguageService)
* - langStats 聚合 → 主语言推断(委托 LanguageService)
* - 主语言 → 语言扩展字段(分析维度、典型模式、反模式、Guard 规则等)
*
* 注册表驱动:
* 所有语言知识集中在 LANG_REGISTRY 中,新增语言只需添加条目即可。
* 覆盖 LanguageService.KNOWN_PROGRAMMING_LANGS 全部 14 种编程语言。
*/
import { LanguageService } from '#shared/LanguageService.js';
/** 根据文件扩展名推断语言 — 委托给 LanguageService(唯一来源) */
export function inferLang(filename) {
return LanguageService.inferLang(filename);
}
/** 从 langStats 推断主语言 — 委托给 LanguageService(唯一来源) */
export function detectPrimaryLanguage(langStats) {
return LanguageService.detectPrimary(langStats);
}
// ═══════════════════════════════════════════════════════════
// 语言扩展注册表 — 按 lang ID 索引
// ═══════════════════════════════════════════════════════════
/** JS/TS 共享扩展生成器(根据具体 lang 微调差异点) */
function _buildJsTsEntry(lang) {
const isTs = lang === 'typescript';
return {
extraDimensions: [
{
id: 'module-system',
label: '模块系统',
guide: 'ESM vs CJS、dynamic import、barrel export、tree-shaking',
},
{
id: 'type-safety',
label: '类型安全',
guide: isTs
? 'strict 模式、泛型、类型守卫、Utility Types、satisfies 操作符'
: 'JSDoc 类型标注、.d.ts 声明、@ts-check',
},
{
id: 'async-pattern',
label: '异步模式',
guide: 'Promise 链、async/await、Error 处理、AbortController、AsyncIterator',
},
{
id: 'framework-convention',
label: '框架约定',
guide: 'React Hooks/Vue Composition/Node.js 中间件/Svelte runes 等框架特有模式',
},
],
typicalPatterns: [
'async/await + try-catch 错误处理',
'barrel export (index.ts re-export)',
isTs ? '泛型约束 <T extends Base>、satisfies 编译期验证' : 'JSDoc @param/@returns 类型标注',
'Optional chaining (?.) + nullish coalescing (??)',
'Factory function / 闭包替代 class',
'Event emitter / pub-sub 解耦',
isTs ? 'Discriminated union 状态建模' : 'Symbol 作为私有 key',
],
commonAntiPatterns: [
{ bad: 'any 类型滥用', why: '丧失类型安全', fix: '定义具体接口或泛型' },
{ bad: '.catch() 空回调', why: '静默吞掉错误', fix: '记录日志或 re-throw' },
{ bad: 'callback hell', why: '嵌套层级过深难以维护', fix: 'async/await 改写' },
{
bad: 'for...in 遍历数组',
why: '遍历原型链属性、顺序不保证',
fix: 'for...of 或 Array 方法',
},
],
suggestedGuardRules: [
...(isTs
? [
{
pattern: ': any',
severity: 'warning',
message: '避免 any 类型,使用 unknown 或具体类型',
},
]
: []),
{ pattern: '\\.catch\\(\\(\\)\\s*=>', severity: 'info', message: 'catch 回调不应为空' },
{ pattern: 'console\\.log', severity: 'info', message: '生产代码移除 console.log' },
{ pattern: 'eval\\(', severity: 'error', message: '禁止使用 eval,存在安全风险' },
],
agentCautions: [
'使用 ESM (import/export) 而非 CJS (require/module.exports)',
'异步函数必须处理错误 (try-catch 或 .catch)',
isTs
? '启用 strict 模式,优先使用 unknown 替代 any'
: '使用 JSDoc 或 @ts-check 标注关键函数类型',
'Node.js 中注意 unhandledRejection 处理',
'优先使用 structuredClone() 深拷贝,避免 JSON.parse(JSON.stringify())',
],
};
}
const LANG_REGISTRY = Object.freeze({
// ── Swift ──────────────────────────────────────────────────
swift: {
extraDimensions: [
{
id: 'concurrency',
label: 'Swift Concurrency',
guide: 'async/await、Actor、@Sendable、TaskGroup、MainActor、AsyncStream 用法',
},
{
id: 'protocol-oriented',
label: '面向协议编程',
guide: 'Protocol 扩展、条件一致性、PAT (Protocol with Associated Type)、some/any 关键字',
},
{
id: 'property-wrapper',
label: 'Property Wrapper',
guide: '@Published、@State、@Environment、@Observable (Observation)、自定义 Property Wrapper',
},
{
id: 'value-semantics',
label: '值语义',
guide: 'struct vs class 决策、COW (Copy-on-Write)、Equatable/Hashable、~Copyable (non-copyable types)',
},
],
typicalPatterns: [
'Result<Success, Failure> 统一错误处理',
'Protocol + Extension 默认实现',
'@MainActor 标注 UI 相关类',
'Combine Publisher / AsyncStream 数据流',
'enum + associated value 状态建模',
'Codable 自定义 CodingKeys',
'@Observable 宏 (Observation 框架)',
],
commonAntiPatterns: [
{ bad: '强制 try! / as! 解包', why: '运行时 crash', fix: 'guard let / if let / do-catch' },
{
bad: 'DispatchQueue.main.async 更新 UI',
why: 'Swift Concurrency 下造成 data race',
fix: '@MainActor',
},
{
bad: '闭包中不用 [weak self]',
why: '循环引用导致内存泄漏',
fix: '[weak self] / [unowned self]',
},
{
bad: '大量使用 AnyView 擦除类型',
why: 'SwiftUI diff 性能下降',
fix: '使用泛型或 @ViewBuilder',
},
],
suggestedGuardRules: [
{ pattern: 'try!', severity: 'warning', message: '避免 force try,使用 do-catch' },
{ pattern: 'as!', severity: 'warning', message: '避免 force cast,使用 as?' },
{ pattern: 'DispatchQueue\\.main', severity: 'info', message: '考虑使用 @MainActor 替代' },
{ pattern: 'AnyView', severity: 'info', message: '避免 AnyView,使用泛型或 @ViewBuilder' },
],
agentCautions: [
'新代码优先使用 Swift Concurrency (async/await) 而非 GCD/DispatchQueue',
'UI 相关类和方法标注 @MainActor',
'优先使用 struct(值类型),class 仅在需要引用语义时使用',
'闭包捕获 self 时必须使用 [weak self] 或 [unowned self]',
'使用 guard let 提前返回,避免嵌套 if let',
],
},
// ── Objective-C ────────────────────────────────────────────
objectivec: {
extraDimensions: [
{
id: 'memory-management',
label: '内存管理',
guide: 'ARC 下的 strong/weak/unsafe_unretained、autorelease、dealloc 模式',
},
{
id: 'category-extension',
label: 'Category/Extension',
guide: 'Category 方法命名冲突、Class Extension 私有属性',
},
{
id: 'block-pattern',
label: 'Block 模式',
guide: 'Block 循环引用、__weak/__strong dance、Block 作为回调',
},
{
id: 'nullability',
label: 'Nullability 标注',
guide: 'nullable/nonnull/NS_ASSUME_NONNULL、与 Swift 互操作',
},
],
typicalPatterns: [
'delegate + protocol 回调模式',
'Category 扩展系统类',
'__weak typeof(self) weakSelf = self',
'NS_ASSUME_NONNULL_BEGIN/END 包裹头文件',
'dispatch_once 单例',
'KVO 属性观察',
],
commonAntiPatterns: [
{ bad: 'Block 内直接引用 self', why: '循环引用', fix: '__weak + __strong dance' },
{
bad: '头文件缺少 nullability 标注',
why: 'Swift 桥接时全部变为 optional',
fix: 'NS_ASSUME_NONNULL + 显式 nullable',
},
{
bad: 'Category 方法不带前缀',
why: '与系统方法/其他库冲突',
fix: '加项目前缀如 xx_methodName',
},
],
suggestedGuardRules: [
{ pattern: '\\[self\\s', severity: 'warning', message: 'Block 内直接引用 self,考虑 __weak' },
{
pattern: '@property.*assign.*id',
severity: 'warning',
message: '对象属性使用 strong/weak 替代 assign',
},
],
agentCautions: [
'ObjC 头文件必须包含 NS_ASSUME_NONNULL_BEGIN/END',
'Category 方法名加项目前缀避免冲突',
'Block 回调注意 __weak/__strong self dance',
'dealloc 中移除 KVO 观察者和 NSNotification 订阅',
],
},
// ── Python ─────────────────────────────────────────────────
python: {
extraDimensions: [
{
id: 'type-hints',
label: '类型注解',
guide: 'typing 模块、Protocol、TypeVar、Generic、dataclass、TypeAlias (3.12+)',
},
{
id: 'async-io',
label: '异步 IO',
guide: 'asyncio、aiohttp、async generators、TaskGroup (3.11+)',
},
{
id: 'package-structure',
label: '包结构',
guide: '__init__.py、相对导入、pyproject.toml、src-layout',
},
{
id: 'testing',
label: '测试模式',
guide: 'pytest fixtures、parametrize、mock/patch、conftest.py 层级',
},
],
typicalPatterns: [
'dataclass / pydantic BaseModel 数据建模',
'context manager (with statement / @contextmanager)',
'decorator 横切关注点',
'typing.Protocol 鸭子类型接口',
'generator / yield 惰性求值',
'match-case 结构化模式匹配 (3.10+)',
'pathlib.Path 替代 os.path 字符串操作',
],
commonAntiPatterns: [
{
bad: 'bare except:',
why: '捕获所有异常包括 SystemExit/KeyboardInterrupt',
fix: 'except Exception as e:',
},
{
bad: '可变默认参数 def f(x: any[]=[])',
why: '函数间共享可变状态',
fix: 'def f(x=None): x = x or []',
},
{ bad: 'import *', why: '污染命名空间、难以追踪来源', fix: '显式导入: from mod import name' },
{ bad: '全局可变状态', why: '并发不安全、测试困难', fix: '依赖注入或函数参数传递' },
],
suggestedGuardRules: [
{
pattern: 'except:',
severity: 'warning',
message: '避免 bare except,至少 except Exception',
},
{ pattern: 'import \\*', severity: 'warning', message: '避免 wildcard import,使用显式导入' },
{
pattern: 'os\\.system\\(',
severity: 'error',
message: '使用 subprocess.run() 替代 os.system()',
},
{ pattern: 'eval\\(', severity: 'error', message: '禁止 eval(),存在代码注入风险' },
],
agentCautions: [
'函数签名使用 type hints (PEP 484+)',
'使用 dataclass 或 pydantic 建模数据,避免裸 dict',
'避免 bare except,至少 except Exception',
'使用 pathlib.Path 处理文件路径',
'异步代码使用 asyncio.TaskGroup (3.11+) 做结构化并发',
],
},
// ── Kotlin ─────────────────────────────────────────────────
kotlin: {
extraDimensions: [
{
id: 'coroutines',
label: '协程',
guide: 'suspend、Flow、CoroutineScope、Dispatchers、structured concurrency',
},
{
id: 'null-safety',
label: '空安全',
guide: '?.、!!、let、elvis ?:、requireNotNull、lateinit',
},
{
id: 'dsl-builder',
label: 'DSL/Builder',
guide: 'Kotlin DSL、buildList、apply/run/let/also 作用域函数',
},
{
id: 'multiplatform',
label: 'Kotlin Multiplatform',
guide: 'expect/actual、共享模块、平台特定实现',
},
],
typicalPatterns: [
'sealed class/interface 状态建模',
'data class 值对象',
'extension function 扩展已有类',
'Flow 链式异步流',
'companion object 工厂方法',
'when 表达式穷举枚举/sealed class',
'inline function + reified 泛型',
],
commonAntiPatterns: [
{ bad: '!! 强制非空断言', why: '运行时 NPE', fix: '?.let {} 或 elvis ?: defaultValue' },
{
bad: 'GlobalScope.launch',
why: '泄漏协程,无法取消',
fix: '使用 viewModelScope/lifecycleScope',
},
{ bad: 'var 过度使用', why: '可变状态难以追踪', fix: '优先使用 val(不可变)' },
],
suggestedGuardRules: [
{ pattern: '!!', severity: 'warning', message: '避免 !! 操作符,使用 ?.let 或 elvis ?:' },
{
pattern: 'GlobalScope',
severity: 'warning',
message: '使用结构化并发 scope 替代 GlobalScope',
},
{ pattern: 'lateinit', severity: 'info', message: '确认 lateinit 使用合理,考虑 lazy 替代' },
],
agentCautions: [
'避免 !! 操作符,使用安全调用 ?.let 或 elvis ?: ',
'协程使用结构化并发 (viewModelScope/lifecycleScope)',
'优先 data class + sealed class/interface 建模',
'利用 when 表达式穷举所有分支',
'优先使用 val 不可变声明',
],
},
// ── Java ───────────────────────────────────────────────────
java: {
extraDimensions: [
{
id: 'concurrency',
label: '并发',
guide: 'synchronized、ExecutorService、CompletableFuture、虚拟线程 (21+)、StructuredTaskScope (preview)',
},
{ id: 'generics', label: '泛型', guide: '类型擦除、通配符 <? extends/super>、类型安全容器' },
{
id: 'modern-java',
label: '现代 Java',
guide: 'record (16+)、sealed class (17+)、pattern matching (21+)、text block',
},
],
typicalPatterns: [
'Builder 模式构造复杂对象',
'Stream API 集合处理',
'Optional 空值处理',
'record 类型替代 POJO (Java 16+)',
'依赖注入 (@Inject/@Autowired)',
'sealed interface + record 代数数据类型 (Java 17+)',
'try-with-resources 自动关闭资源',
],
commonAntiPatterns: [
{
bad: '返回 null 表示不存在',
why: '调用方容易忘记 null check',
fix: 'Optional<T> 或 @Nullable 标注',
},
{ bad: 'raw type 泛型', why: '运行时 ClassCastException', fix: '指定具体类型参数' },
{ bad: 'catch (Exception e) {}', why: '静默吞掉异常', fix: '至少记录日志或 rethrow' },
{
bad: 'new Thread().start()',
why: '无法管理线程生命周期',
fix: 'ExecutorService 或虚拟线程',
},
],
suggestedGuardRules: [
{
pattern: 'catch\\s*\\(\\s*Exception',
severity: 'info',
message: '避免宽泛的 Exception catch,使用具体异常类型',
},
{
pattern: '\\.printStackTrace\\(\\)',
severity: 'warning',
message: '使用日志框架替代 printStackTrace',
},
{
pattern: 'new Thread\\(',
severity: 'info',
message: '考虑使用 ExecutorService 或虚拟线程',
},
],
agentCautions: [
'优先使用 Optional 处理可空返回值',
'使用 Stream API 替代手动循环',
'并发使用 ExecutorService 或虚拟线程 (21+) 而非 raw Thread',
'使用 try-with-resources 管理 AutoCloseable 资源',
'数据载体优先使用 record (16+) 替代手写 POJO',
],
},
// ── Go ─────────────────────────────────────────────────────
go: {
extraDimensions: [
{
id: 'goroutine',
label: 'Goroutine/Channel',
guide: '并发模式、channel、select、context 传播、errgroup',
},
{
id: 'error-handling',
label: '错误处理',
guide: 'error interface、errors.Is/As、sentinel errors、%w wrap、多错误 errors.Join (1.20+)',
},
{
id: 'interface',
label: '接口设计',
guide: '隐式实现、小接口、io.Reader/Writer 组合、Accept interfaces return structs',
},
],
typicalPatterns: [
'if err != nil { return err }',
'context.Context 贯穿调用链',
'functional options 模式',
'table-driven tests',
'interface 在消费侧定义',
'defer 确保资源清理',
'embed 嵌入结构体组合复用',
],
commonAntiPatterns: [
{ bad: '忽略 error 返回值 _', why: '静默丢失错误信息', fix: '检查并传播 error' },
{
bad: 'goroutine 无退出控制',
why: '泄漏 goroutine',
fix: 'context.WithCancel / done channel',
},
{ bad: 'init() 函数过度使用', why: '隐式副作用、测试困难', fix: '显式初始化函数 + 依赖注入' },
{ bad: 'sync.Mutex 包级变量', why: '全局可变状态', fix: '封装到 struct 内' },
],
suggestedGuardRules: [
{
pattern: 'panic\\(',
severity: 'warning',
message: '仅在不可恢复错误时使用 panic,正常错误返回 error',
},
{
pattern: 'log\\.Fatal',
severity: 'info',
message: 'log.Fatal 会调用 os.Exit,确认场景合理',
},
{
pattern: 'go func\\(',
severity: 'info',
message: '确保 goroutine 有退出路径(context/done channel)',
},
],
agentCautions: [
'函数必须检查并传播 error,不要忽略 _',
'使用 context.Context 作为第一个参数',
'goroutine 确保有退出路径,使用 errgroup 管理并发',
'defer 放在资源获取之后立即声明',
'接口在消费方定义,保持小而精',
],
},
// ── Rust ───────────────────────────────────────────────────
rust: {
extraDimensions: [
{
id: 'ownership',
label: '所有权/借用',
guide: 'ownership、borrowing、lifetime、Clone vs Copy、interior mutability (RefCell/Mutex)',
},
{
id: 'error-handling',
label: '错误处理',
guide: 'Result<T,E>、? 操作符、thiserror/anyhow、自定义 Error enum',
},
{
id: 'trait-system',
label: 'Trait 系统',
guide: 'trait bound、impl Trait、dyn Trait、derive 宏、blanket impl',
},
{
id: 'async-runtime',
label: '异步运行时',
guide: 'tokio/async-std、Future、Pin、async trait、select!',
},
],
typicalPatterns: [
'Result<T, E> + ? 操作符链式传播',
'enum 代数数据类型 + pattern matching',
'impl Trait 返回类型 / dyn Trait 动态分发',
'Builder 模式 (consuming self)',
'#[derive(Debug, Clone, ...)] 自动实现',
'From/Into trait 类型转换',
'Iterator 链式组合子',
],
commonAntiPatterns: [
{ bad: '.unwrap() / .expect() 泛滥', why: '生产环境 panic', fix: '? 操作符或 match' },
{ bad: '.clone() 逃避借用检查', why: '隐藏性能问题', fix: '重新设计所有权或使用引用' },
{
bad: 'Arc<Mutex<T>> 过度使用',
why: '运行时锁开销',
fix: '优先考虑消息传递 (channel) 或更细粒度设计',
},
],
suggestedGuardRules: [
{
pattern: '\\.unwrap\\(\\)',
severity: 'warning',
message: '避免 unwrap(),使用 ? 或 expect("reason")',
},
{
pattern: 'unsafe\\s*\\{',
severity: 'warning',
message: '审查 unsafe 代码块,确保 safety invariant 有文档',
},
{
pattern: 'todo!\\(\\)|unimplemented!\\(\\)',
severity: 'info',
message: '确认 todo!/unimplemented! 不会进入生产环境',
},
],
agentCautions: [
'优先使用借用 (&T / &mut T) 而非 clone',
'错误类型使用 thiserror 定义,应用层使用 anyhow',
'避免 unwrap(),使用 ? 或 expect("有意义的说明")',
'unsafe 代码块必须写 // SAFETY: 注释说明 invariant',
'优先使用 Iterator 组合子替代手动循环',
],
},
// ── C ──────────────────────────────────────────────────────
c: {
extraDimensions: [
{
id: 'memory-safety',
label: '内存安全',
guide: 'malloc/free 配对、指针生命周期、缓冲区溢出防范、AddressSanitizer',
},
{
id: 'preprocessor',
label: '预处理器',
guide: '#define 宏、条件编译、include guard / #pragma once、X-Macro 模式',
},
{
id: 'api-design',
label: 'API 设计',
guide: 'opaque pointer(PIMPL)、const 正确性、错误码约定、头文件组织',
},
],
typicalPatterns: [
'struct + 函数指针模拟 OOP',
'typedef 定义公共 API 类型',
'const 修饰只读参数',
'错误码 + goto cleanup 资源释放',
'include guard (#ifndef ... #define ... #endif)',
'opaque pointer 隐藏实现细节',
],
commonAntiPatterns: [
{
bad: 'malloc 后不检查 NULL',
why: 'OOM 时解引用空指针 → crash',
fix: 'if (!ptr) { handle_error(); }',
},
{
bad: '缓冲区无边界检查',
why: '缓冲区溢出 → 安全漏洞',
fix: '使用 snprintf/strncat + 显式长度参数',
},
{
bad: 'malloc/free 未配对',
why: '内存泄漏或 double free',
fix: '集中管理资源生命周期、使用 goto cleanup 模式',
},
{
bad: '函数式宏无括号包裹参数',
why: '宏展开时运算优先级错误',
fix: '#define MAX(a,b) ((a) > (b) ? (a) : (b))',
},
],
suggestedGuardRules: [
{
pattern: 'gets\\(',
severity: 'error',
message: '禁止使用 gets(),已被移除(CVE 风险),使用 fgets()',
},
{
pattern: 'sprintf\\(',
severity: 'warning',
message: '使用 snprintf() 替代 sprintf(),防止缓冲区溢出',
},
{
pattern: 'strcpy\\(',
severity: 'warning',
message: '使用 strncpy()/strlcpy() 替代 strcpy()',
},
{
pattern: 'atoi\\(',
severity: 'info',
message: '使用 strtol() 替代 atoi(),可检测解析错误',
},
],
agentCautions: [
'malloc/calloc 后必须检查返回值是否为 NULL',
'使用 snprintf/strncat 等带长度参数的安全函数',
'每个 malloc 必须有对应 free,推荐 goto cleanup 模式',
'头文件使用 include guard 或 #pragma once',
'函数参数中只读指针用 const 修饰',
],
},
// ── C++ ────────────────────────────────────────────────────
cpp: {
extraDimensions: [
{
id: 'raii',
label: 'RAII / 智能指针',
guide: 'unique_ptr、shared_ptr、weak_ptr、自定义 deleter、make_unique/make_shared',
},
{
id: 'templates',
label: '模板 / Concepts',
guide: '函数模板、类模板、SFINAE、Concepts (C++20)、requires 表达式',
},
{
id: 'move-semantics',
label: '移动语义',
guide: '右值引用 (&&)、std::move、完美转发 (std::forward)、Rule of 0/3/5',
},
{
id: 'modern-cpp',
label: '现代 C++ 特性',
guide: 'constexpr、std::optional、std::variant、structured bindings、ranges (C++20)',
},
],
typicalPatterns: [
'RAII 管理资源 (unique_ptr/shared_ptr)',
'range-based for 遍历容器',
'constexpr 编译期求值',
'override + final 虚函数覆盖',
'std::optional 替代 nullable pointer',
'std::variant + std::visit 类型安全联合',
'auto + structured bindings 简化声明',
],
commonAntiPatterns: [
{
bad: 'new/delete 手动管理内存',
why: '容易泄漏,异常不安全',
fix: 'std::make_unique / std::make_shared',
},
{ bad: 'catch(...) 吃掉所有异常', why: '隐藏真实错误', fix: '捕获具体异常类型并处理' },
{ bad: '对象切片 (slicing)', why: '派生类信息丢失', fix: '使用指针/引用传递多态对象' },
{
bad: '#define 常量/函数',
why: '无类型检查、调试困难',
fix: 'constexpr 变量 / inline 函数 / 模板',
},
],
suggestedGuardRules: [
{
pattern: '\\bnew\\b(?!.*unique_ptr|.*shared_ptr)',
severity: 'warning',
message: '优先使用 make_unique/make_shared 替代 raw new',
},
{ pattern: '\\bdelete\\b', severity: 'warning', message: '避免手动 delete,使用智能指针' },
{
pattern: 'using namespace std',
severity: 'info',
message: '避免在头文件中使用 using namespace',
},
{
pattern: 'reinterpret_cast',
severity: 'warning',
message: '审查 reinterpret_cast 使用是否合理',
},
],
agentCautions: [
'使用智能指针 (unique_ptr/shared_ptr) 而非 raw new/delete',
'虚函数覆盖必须加 override 关键字',
'优先使用 constexpr 替代 #define 宏常量',
'遵循 Rule of Zero — 除非必要,不自定义析构/拷贝/移动',
'头文件使用前置声明减少编译依赖',
],
},
// ── Ruby ───────────────────────────────────────────────────
ruby: {
extraDimensions: [
{
id: 'metaprogramming',
label: '元编程',
guide: 'define_method、method_missing、class_eval、open class、DSL 构建',
},
{
id: 'block-proc-lambda',
label: 'Block/Proc/Lambda',
guide: 'yield、block_given?、Proc.new vs lambda、& 转换',
},
{
id: 'convention-over-config',
label: '约定优于配置',
guide: 'Rails 约定 (命名/目录结构)、ActiveRecord 模式、concern 复用',
},
],
typicalPatterns: [
'block + yield 迭代器模式',
'module include/prepend 混入',
'attr_accessor/attr_reader 声明式属性',
'Symbol 作为 Hash key',
'Enumerable 方法链 (map/select/reduce)',
'begin-rescue-ensure 异常处理',
'frozen_string_literal 优化字符串',
],
commonAntiPatterns: [
{
bad: 'method_missing 无 respond_to_missing?',
why: '反射 API 行为不一致',
fix: '同时定义 respond_to_missing?',
},
{ bad: 'Monkey-patch 核心类', why: '全局影响、版本升级冲突', fix: 'Refinements 或委托模式' },
{
bad: 'N+1 查询 (ActiveRecord)',
why: '数据库性能严重退化',
fix: 'includes/preload 预加载关联',
},
],
suggestedGuardRules: [
{
pattern: 'eval\\(',
severity: 'error',
message: '避免 eval,存在代码注入风险,使用 send/public_send',
},
{
pattern: 'method_missing',
severity: 'info',
message: '确认配套定义了 respond_to_missing?',
},
{
pattern: '\\.find_each|\\.all\\.each',
severity: 'info',
message: '大数据集使用 find_each / in_batches 分批处理',
},
],
agentCautions: [
'在文件头添加 # frozen_string_literal: true',
'元编程 (method_missing) 必须配套 respond_to_missing?',
'ActiveRecord 使用 includes/preload 避免 N+1',
'优先使用 module + include 组合,慎用 monkey-patching',
'异常处理使用 begin-rescue-ensure,不要 rescue Exception',
],
},
// ── Dart ───────────────────────────────────────────────────
dart: {
extraDimensions: [
{
id: 'null-safety',
label: '空安全',
guide: '?、!、late、required、null-aware operators (?., ??, ??=)',
},
{
id: 'widget-composition',
label: 'Widget 组合 (Flutter)',
guide: 'StatelessWidget/StatefulWidget、Widget 拆分、const 构造器、InheritedWidget',
},
{
id: 'async-patterns',
label: '异步模式',
guide: 'Future、Stream、async*/yield*、Isolate 并行计算',
},
{
id: 'state-management',
label: '状态管理',
guide: 'Provider/Riverpod/Bloc/GetX、单向数据流、响应式编程',
},
],
typicalPatterns: [
'const 构造器优化 Widget rebuild',
'StatelessWidget 优先、StatefulWidget 按需',
'extension methods 扩展已有类型',
'freezed + json_serializable 生成不可变模型',
'named parameters + required 提升可读性',
'Stream.listen / StreamBuilder 响应式 UI',
'sealed class (Dart 3) 穷举模式匹配',
],
commonAntiPatterns: [
{
bad: '在 build() 中调用 setState 或异步操作',
why: '无限重建循环',
fix: '在 initState/事件回调中处理',
},
{
bad: '单个 Widget 过大 (>200 行)',
why: '难以维护和复用',
fix: '拆分为小 Widget + const 子树',
},
{
bad: '滥用 late 关键字',
why: '运行时 LateInitializationError',
fix: '使用 nullable (?) 或在声明处初始化',
},
{
bad: 'setState 管理全局状态',
why: '状态散落、难以追踪',
fix: '使用 Provider/Riverpod 等状态管理方案',
},
],
suggestedGuardRules: [
{ pattern: 'print\\(', severity: 'info', message: '生产代码使用 logger 替代 print()' },
{
pattern: '!\\s*\\.',
severity: 'info',
message: '审查 ! (force-unwrap) 使用,考虑 ?. 安全访问',
},
{ pattern: 'dynamic', severity: 'warning', message: '避免 dynamic 类型,使用具体类型或泛型' },
],
agentCautions: [
'优先使用 const 构造器优化 Widget 树性能',
'每个 Widget 保持单一职责,超过 100 行应考虑拆分',
'使用 sealed class (Dart 3+) 进行穷举模式匹配',
'异步操作使用 Future/Stream,计算密集型使用 Isolate',
'优先用 final 声明局部变量和类属性',
],
},
// ── C# ─────────────────────────────────────────────────────
csharp: {
extraDimensions: [
{
id: 'async-await',
label: 'async/await',
guide: 'Task、ValueTask、IAsyncEnumerable、ConfigureAwait、CancellationToken',
},
{
id: 'linq',
label: 'LINQ',
guide: '查询表达式、方法链、延迟执行、IQueryable vs IEnumerable',
},
{
id: 'pattern-matching',
label: '模式匹配',
guide: 'switch expression、is pattern、property pattern、list pattern (C# 11)',
},
{
id: 'dependency-injection',
label: '依赖注入',
guide: 'IServiceCollection、Scoped/Transient/Singleton、IOptions<T>、Hosted Services',
},
],
typicalPatterns: [
'async Task 方法 + CancellationToken',
'LINQ 方法链处理集合',
'record 类型 (C# 9+) 不可变数据',
'nullable reference types (#nullable enable)',
'依赖注入 (IServiceCollection / constructor injection)',
'switch expression 替代 if-else 链',
'using declaration 自动释放资源',
],
commonAntiPatterns: [
{ bad: 'async void 方法', why: '异常无法捕获、调用方无法 await', fix: '返回 async Task' },
{ bad: '.Result / .Wait() 阻塞', why: '线程池饥饿 / UI 线程死锁', fix: 'await 全程异步' },
{
bad: 'IDisposable 未 Dispose',
why: '资源泄漏 (连接/句柄)',
fix: 'using statement/declaration',
},
{
bad: 'catch (Exception: any) { } 空处理',
why: '静默吞掉错误',
fix: '记录日志或 rethrow (throw;)',
},
],
suggestedGuardRules: [
{ pattern: 'async void', severity: 'warning', message: '避免 async void,使用 async Task' },
{
pattern: '\\.Result\\b|\\.Wait\\(',
severity: 'warning',
message: '避免同步阻塞异步方法,使用 await',
},
{
pattern: 'catch\\s*\\(Exception',
severity: 'info',
message: '避免宽泛 catch Exception,捕获具体异常类型',
},
],
agentCautions: [
'async 方法返回 Task/ValueTask,不要 async void',
'异步代码全程 await,避免 .Result/.Wait() 死锁',
'IDisposable 资源使用 using statement 确保释放',
'启用 nullable reference types (#nullable enable)',
'使用 record (C# 9+) 构建不可变数据传输对象',
],
},
});
// ═══════════════════════════════════════════════════════════
// buildLanguageExtension — 公共 API
// ═══════════════════════════════════════════════════════════
/**
* 根据主语言构建语言扩展字段
* 包含:语言特有的分析关注点、典型模式、反模式、Guard 规则、Agent 注意事项
*
* @param lang 规范化语言 ID (如 'swift', 'typescript')
* @returns }
*/
export function buildLanguageExtension(lang) {
const base = {
language: lang ?? 'unknown',
customFields: {},
extraDimensions: [],
typicalPatterns: [],
commonAntiPatterns: [],
suggestedGuardRules: [],
agentCautions: [],
};
// JS/TS 动态生成(有 lang-specific 差异点)
if (lang === 'javascript' || lang === 'typescript') {
const entry = _buildJsTsEntry(lang);
return Object.assign(base, entry);
}
// 其他语言从注册表查找
if (lang) {
const entry = LANG_REGISTRY[lang];
if (entry) {
return Object.assign(base, entry);
}
}
return base;
}