UNPKG

autosnippet

Version:

Extract code patterns into a knowledge base for AI coding assistants

242 lines (241 loc) 10.2 kB
/** * Node.js Server Enhancement Pack * 条件: { languages: ['typescript', 'javascript'], frameworks: ['node-server', 'nestjs'] } * * 覆盖 Node.js 后端生态: * - Express / Koa / Hono 中间件链 * - Fastify 插件体系 + Schema Validation * - NestJS Module / DI / Guard / Pipe / Interceptor * - 错误处理与日志中间件 */ import { EnhancementPack } from './EnhancementPack.js'; class NodeServerEnhancement extends EnhancementPack { get id() { return 'node-server'; } get displayName() { return 'Node.js Server (Express/Fastify/NestJS) Enhancement'; } get conditions() { return { languages: ['typescript', 'javascript'], frameworks: ['node-server', 'nestjs'] }; } getExtraDimensions() { return [ { id: 'middleware-analysis', label: '中间件链分析', guide: 'Middleware 链路分析、错误处理中间件、路由守卫、认证/鉴权中间件、中间件执行顺序', tierHint: 2, knowledgeTypes: ['architecture', 'code-pattern'], skillWorthy: true, dualOutput: true, skillMeta: { name: 'project-node-middleware', description: 'Node.js middleware chain and error handling patterns (auto-generated by enhancement)', }, }, { id: 'nestjs-module-scan', label: 'NestJS 模块 DI 分析', guide: 'NestJS 模块拓扑分析 — @Module imports/exports/providers/controllers 依赖图、Dynamic Module (forRoot/forRootAsync)、Custom Provider (useClass/useFactory/useValue)、Scope (DEFAULT/REQUEST/TRANSIENT)', tierHint: 2, knowledgeTypes: ['architecture'], skillWorthy: true, dualOutput: true, skillMeta: { name: 'project-nestjs-modules', description: 'NestJS module dependency topology, DI providers and scopes (auto-generated by enhancement)', }, }, { id: 'node-validation-scan', label: '请求验证模式分析', guide: '请求验证模式分析 — Zod/Joi/class-validator schema 定义、Fastify JSON Schema、NestJS ValidationPipe、DTO 类与验证装饰器', tierHint: 2, knowledgeTypes: ['code-pattern', 'code-standard'], skillWorthy: true, dualOutput: true, skillMeta: { name: 'project-node-validation', description: 'Node.js request validation patterns — Zod/Joi/class-validator schemas (auto-generated by enhancement)', }, }, ]; } getGuardRules() { return [ { ruleId: 'node-no-sync-io', category: 'performance', dimension: 'file', severity: 'warning', languages: ['typescript', 'javascript'], pattern: /(?:readFileSync|writeFileSync|appendFileSync|mkdirSync|readdirSync|statSync|existsSync|unlinkSync|renameSync|copyFileSync|accessSync)/, message: '避免在请求路径中使用同步 IO 操作', }, { ruleId: 'node-error-handler', category: 'correctness', dimension: 'file', severity: 'info', languages: ['typescript', 'javascript'], pattern: /app\.use\(\s*\(\s*err\s*,\s*req\s*,\s*res\s*,\s*next\s*\)/, message: 'Express 应用需要注册 4 参数错误处理中间件', }, { ruleId: 'node-no-unhandled-promise', category: 'correctness', dimension: 'file', severity: 'warning', languages: ['typescript', 'javascript'], pattern: /\.then\s*\([^)]*\)\s*(?!\.catch)/, message: 'Promise 链应包含 .catch() 处理或使用 async/await + try/catch — 未处理的 rejection 会导致进程崩溃', }, { ruleId: 'nestjs-circular-dependency', category: 'correctness', dimension: 'file', severity: 'warning', languages: ['typescript', 'javascript'], pattern: /forwardRef\s*\(\s*\(\)\s*=>/, message: 'forwardRef 说明存在循环依赖 — 考虑重构模块结构或使用事件驱动解耦', }, { ruleId: 'nestjs-no-any-response', category: 'style', dimension: 'file', severity: 'info', languages: ['typescript', 'javascript'], pattern: /@(?:Get|Post|Put|Delete|Patch)\s*\([^)]*\)\s*\n\s*(?:async\s+)?\w+\([^)]*\)\s*(?::\s*any)?/, message: 'NestJS controller 方法建议声明返回类型 DTO — 便于 Swagger 文档生成与类型安全', }, { ruleId: 'node-exposed-secrets', category: 'safety', dimension: 'file', severity: 'error', languages: ['typescript', 'javascript'], pattern: /(?:password|secret|api[_-]?key|token)\s*[:=]\s*['"][^'"]+['"]/i, message: '硬编码机密信息 — 使用环境变量或 Secret Manager', }, ]; } detectPatterns(astSummary) { const patterns = []; // ── Express/Koa middleware ((req, res, next) signature) ── for (const m of astSummary.methods || []) { if (!m.className && m.paramCount === 3) { patterns.push({ type: 'middleware', methodName: m.name, line: m.line, confidence: 0.6 }); } } // ── NestJS Controllers ── for (const cls of astSummary.classes || []) { if (cls.decorators?.some((d) => /@Controller/.test(d))) { patterns.push({ type: 'nestjs-controller', className: cls.name, line: cls.line, confidence: 0.95, }); } if (cls.decorators?.some((d) => /@Injectable/.test(d))) { patterns.push({ type: 'nestjs-injectable', className: cls.name, line: cls.line, confidence: 0.95, }); } if (cls.decorators?.some((d) => /@Module/.test(d))) { patterns.push({ type: 'nestjs-module', className: cls.name, line: cls.line, confidence: 0.95, }); } } // ── NestJS Guards / Pipes / Interceptors / Filters ── for (const cls of astSummary.classes || []) { const implemented = cls.interfaces || []; if (implemented.includes('CanActivate')) { patterns.push({ type: 'nestjs-guard', className: cls.name, line: cls.line, confidence: 0.95, }); } if (implemented.includes('PipeTransform')) { patterns.push({ type: 'nestjs-pipe', className: cls.name, line: cls.line, confidence: 0.95, }); } if (implemented.includes('NestInterceptor')) { patterns.push({ type: 'nestjs-interceptor', className: cls.name, line: cls.line, confidence: 0.95, }); } if (implemented.includes('ExceptionFilter')) { patterns.push({ type: 'nestjs-exception-filter', className: cls.name, line: cls.line, confidence: 0.95, }); } } // ── Fastify plugin pattern (fp(async function)) ── for (const m of astSummary.methods || []) { if (!m.className && m.isExported && m.isAsync) { const nameLower = m.name?.toLowerCase() || ''; if (nameLower.includes('plugin') || nameLower.includes('register')) { patterns.push({ type: 'fastify-plugin', methodName: m.name, line: m.line, confidence: 0.7, }); } } } // ── Validation/DTO classes ── for (const cls of astSummary.classes || []) { const nameLower = cls.name?.toLowerCase() || ''; if (nameLower.endsWith('dto') || nameLower.endsWith('schema') || nameLower.endsWith('validator')) { patterns.push({ type: 'node-dto', className: cls.name, line: cls.line, confidence: 0.8, }); } } // ── Node framework imports ── const serverImports = (astSummary.imports || []).filter((imp) => imp.includes('express') || imp.includes('fastify') || imp.includes('@nestjs') || imp.includes('koa') || imp.includes('hono') || imp.includes('zod') || imp.includes('class-validator') || imp.includes('joi')); if (serverImports.length > 0) { patterns.push({ type: 'node-server-framework-usage', importCount: serverImports.length, confidence: 0.85, }); } return patterns; } } export const pack = new NodeServerEnhancement();