autosnippet
Version:
Extract code patterns into a knowledge base for AI coding assistants
242 lines (241 loc) • 10.2 kB
JavaScript
/**
* 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();