code-simplifier 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/master.js CHANGED
@@ -354,6 +354,123 @@ function isSuperAdmin(data) {
354
354
 
355
355
  console.log('')
356
356
  }
357
+
358
+ /**
359
+ * 增强质量分析(集成 ESLint、多语言、自动修复)
360
+ */
361
+ async enhancedQualityAnalysis(options = {}) {
362
+ console.log(chalk.cyan.bold('\n🔍 增强质量分析'))
363
+ console.log(chalk.gray('='.repeat(70)))
364
+
365
+ const {
366
+ dir = 'src',
367
+ eslint = true,
368
+ multilang = true,
369
+ autofix = false
370
+ } = options
371
+
372
+ const results = {}
373
+
374
+ // 1. 基础质量分析
375
+ console.log(chalk.blue('\n1️⃣ 基础质量分析'))
376
+ const analyzer = require('./quality-analyzer')
377
+ const analysisResult = await analyzer.runQuickCheck()
378
+ results.basic = analysisResult
379
+
380
+ // 2. ESLint 分析(如果启用)
381
+ if (eslint) {
382
+ console.log(chalk.blue('\n2️⃣ ESLint 分析'))
383
+ try {
384
+ const eslintIntegration = require('./eslint-integration')
385
+ const eslintResult = await eslintIntegration.runAnalysis('.', {
386
+ format: 'json',
387
+ fix: autofix
388
+ })
389
+
390
+ if (eslintResult.success) {
391
+ results.eslint = eslintIntegration.integrateWithQualityAnalysis(eslintResult, analysisResult)
392
+ console.log(chalk.green(`✓ ESLint: ${eslintResult.summary.totalErrors} 错误, ${eslintResult.summary.totalWarnings} 警告`))
393
+ } else {
394
+ console.log(chalk.yellow('⚠ ESLint 未配置或不可用'))
395
+ }
396
+ } catch (error) {
397
+ console.log(chalk.gray(`⚠ ESLint 分析失败: ${error.message}`))
398
+ }
399
+ }
400
+
401
+ // 3. 多语言分析(如果启用)
402
+ if (multilang) {
403
+ console.log(chalk.blue('\n3️⃣ 多语言分析'))
404
+ try {
405
+ const multiLang = require('./multi-language-analyzer')
406
+ const langResult = await multiLang.analyze('.')
407
+
408
+ if (langResult.success) {
409
+ results.languages = langResult.languages
410
+ console.log(chalk.green(`✓ 检测到 ${langResult.languages.length} 种语言`))
411
+ langResult.languages.forEach(lang => {
412
+ console.log(chalk.gray(` - ${lang.name} (${lang.confidence})`))
413
+ })
414
+ }
415
+ } catch (error) {
416
+ console.log(chalk.gray(`⚠ 多语言分析失败: ${error.message}`))
417
+ }
418
+ }
419
+
420
+ // 4. 自动修复(如果启用)
421
+ if (autofix) {
422
+ console.log(chalk.blue('\n4️⃣ 自动修复'))
423
+ try {
424
+ const autoFix = require('./auto-fix')
425
+ const fixResult = await autoFix.run({
426
+ dir,
427
+ dryRun: false
428
+ })
429
+
430
+ if (fixResult.success) {
431
+ results.fixes = fixResult
432
+ console.log(chalk.green(`✓ 已修复 ${fixResult.applied} 个问题`))
433
+ }
434
+ } catch (error) {
435
+ console.log(chalk.gray(`⚠ 自动修复失败: ${error.message}`))
436
+ }
437
+ }
438
+
439
+ // 生成综合报告
440
+ console.log(chalk.cyan('\n📊 综合结果'))
441
+ const finalScore = results.eslint?.score || results.basic.score
442
+ console.log(chalk.cyan(` 最终评分: ${finalScore}/100`))
443
+ console.log(chalk.cyan(` 问题总数: ${results.basic.totalIssues}`))
444
+ if (results.eslint) {
445
+ console.log(chalk.red(` ESLint错误: ${results.eslint.eslint.totalErrors}`))
446
+ console.log(chalk.yellow(` ESLint警告: ${results.eslint.eslint.totalWarnings}`))
447
+ }
448
+
449
+ return {
450
+ success: true,
451
+ results,
452
+ score: finalScore
453
+ }
454
+ }
455
+
456
+ /**
457
+ * Git 钩子管理
458
+ */
459
+ async manageGitHooks(options = {}) {
460
+ const gitHooks = require('./git-hooks')
461
+ return await gitHooks.run(options)
462
+ }
463
+
464
+ /**
465
+ * 安装 Git 钩子
466
+ */
467
+ async installGitHooks(options = {}) {
468
+ console.log(chalk.cyan.bold('\n🔧 安装 Git 钩子'))
469
+ console.log(chalk.gray('='.repeat(70)))
470
+
471
+ const gitHooks = require('./git-hooks')
472
+ return await gitHooks.install(options)
473
+ }
357
474
  }
358
475
 
359
476
  module.exports = new ContinuousImprovementMaster()
@@ -0,0 +1,397 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Code-Simplifier 多语言分析器
5
+ */
6
+
7
+ const fs = require('fs-extra')
8
+ const path = require('path')
9
+ const chalk = require('chalk')
10
+
11
+ class MultiLanguageAnalyzer {
12
+ constructor() {
13
+ this.languageConfigs = {
14
+ javascript: {
15
+ name: 'JavaScript',
16
+ extensions: ['.js', '.jsx'],
17
+ patterns: ['**/*.js', '**/*.jsx'],
18
+ complexityKeywords: ['if', 'for', 'while', 'switch', 'catch', 'try'],
19
+ fileIndicators: ['package.json', '.eslintrc.js']
20
+ },
21
+ typescript: {
22
+ name: 'TypeScript',
23
+ extensions: ['.ts', '.tsx'],
24
+ patterns: ['**/*.ts', '**/*.tsx'],
25
+ complexityKeywords: ['if', 'for', 'while', 'switch', 'catch', 'try'],
26
+ fileIndicators: ['tsconfig.json', '.eslintrc.js']
27
+ },
28
+ python: {
29
+ name: 'Python',
30
+ extensions: ['.py'],
31
+ patterns: ['**/*.py'],
32
+ complexityKeywords: ['if', 'for', 'while', 'try', 'except'],
33
+ fileIndicators: ['requirements.txt', 'setup.py', 'Pipfile']
34
+ },
35
+ java: {
36
+ name: 'Java',
37
+ extensions: ['.java'],
38
+ patterns: ['**/*.java'],
39
+ complexityKeywords: ['if', 'for', 'while', 'switch', 'try', 'catch'],
40
+ fileIndicators: ['pom.xml', 'build.gradle', 'build.xml']
41
+ },
42
+ csharp: {
43
+ name: 'C#',
44
+ extensions: ['.cs'],
45
+ patterns: ['**/*.cs'],
46
+ complexityKeywords: ['if', 'for', 'while', 'switch', 'try', 'catch'],
47
+ fileIndicators: ['*.csproj', '*.sln']
48
+ },
49
+ cpp: {
50
+ name: 'C++',
51
+ extensions: ['.cpp', '.cc', '.cxx', '.h', '.hpp'],
52
+ patterns: ['**/*.cpp', '**/*.cc', '**/*.cxx', '**/*.h', '**/*.hpp'],
53
+ complexityKeywords: ['if', 'for', 'while', 'switch', 'try', 'catch'],
54
+ fileIndicators: ['CMakeLists.txt', 'Makefile']
55
+ },
56
+ php: {
57
+ name: 'PHP',
58
+ extensions: ['.php'],
59
+ patterns: ['**/*.php'],
60
+ complexityKeywords: ['if', 'for', 'while', 'switch', 'try', 'catch'],
61
+ fileIndicators: ['composer.json', '*.phpproj']
62
+ },
63
+ ruby: {
64
+ name: 'Ruby',
65
+ extensions: ['.rb'],
66
+ patterns: ['**/*.rb'],
67
+ complexityKeywords: ['if', 'unless', 'while', 'for', 'case', 'begin'],
68
+ fileIndicators: ['Gemfile', '*.gemspec']
69
+ },
70
+ go: {
71
+ name: 'Go',
72
+ extensions: ['.go'],
73
+ patterns: ['**/*.go'],
74
+ complexityKeywords: ['if', 'for', 'switch', 'select'],
75
+ fileIndicators: ['go.mod', 'go.sum']
76
+ },
77
+ rust: {
78
+ name: 'Rust',
79
+ extensions: ['.rs'],
80
+ patterns: ['**/*.rs'],
81
+ complexityKeywords: ['if', 'for', 'while', 'match', 'try'],
82
+ fileIndicators: ['Cargo.toml', 'Cargo.lock']
83
+ },
84
+ kotlin: {
85
+ name: 'Kotlin',
86
+ extensions: ['.kt', '.kts'],
87
+ patterns: ['**/*.kt', '**/*.kts'],
88
+ complexityKeywords: ['if', 'for', 'while', 'when', 'try', 'catch'],
89
+ fileIndicators: ['build.gradle.kts', 'pom.xml']
90
+ },
91
+ swift: {
92
+ name: 'Swift',
93
+ extensions: ['.swift'],
94
+ patterns: ['**/*.swift'],
95
+ complexityKeywords: ['if', 'for', 'while', 'switch', 'guard'],
96
+ fileIndicators: ['Package.swift', '*.xcodeproj']
97
+ }
98
+ }
99
+ }
100
+
101
+ /**
102
+ * 检测项目语言
103
+ */
104
+ async detectLanguage(projectDir) {
105
+ const detectedLanguages = []
106
+
107
+ for (const [langKey, config] of Object.entries(this.languageConfigs)) {
108
+ // 检查文件指示符
109
+ for (const indicator of config.fileIndicators) {
110
+ const matches = await this.findFiles(projectDir, indicator)
111
+ if (matches.length > 0) {
112
+ detectedLanguages.push({
113
+ key: langKey,
114
+ name: config.name,
115
+ confidence: 'high',
116
+ matches: matches.length,
117
+ indicator
118
+ })
119
+ break
120
+ }
121
+ }
122
+ }
123
+
124
+ // 检查文件扩展名
125
+ for (const [langKey, config] of Object.entries(this.languageConfigs)) {
126
+ const files = await this.scanFiles(projectDir, config.patterns)
127
+ if (files.length > 0) {
128
+ // 检查是否已经检测到
129
+ const alreadyDetected = detectedLanguages.find(l => l.key === langKey)
130
+ if (!alreadyDetected) {
131
+ detectedLanguages.push({
132
+ key: langKey,
133
+ name: config.name,
134
+ confidence: files.length > 10 ? 'medium' : 'low',
135
+ files: files.length
136
+ })
137
+ }
138
+ }
139
+ }
140
+
141
+ // 按置信度排序
142
+ return detectedLanguages.sort((a, b) => {
143
+ const confidenceOrder = { high: 3, medium: 2, low: 1 }
144
+ return confidenceOrder[b.confidence] - confidenceOrder[a.confidence]
145
+ })
146
+ }
147
+
148
+ /**
149
+ * 扫描文件
150
+ */
151
+ async scanFiles(projectDir, patterns) {
152
+ const files = []
153
+
154
+ for (const pattern of patterns) {
155
+ const glob = require('glob')
156
+ const matches = await new Promise((resolve, reject) => {
157
+ try {
158
+ glob(pattern, {
159
+ cwd: projectDir,
160
+ ignore: ['node_modules/**', 'dist/**', 'build/**', 'vendor/**', '.git/**'],
161
+ nodir: true
162
+ }, (err, matches) => {
163
+ if (err) resolve([])
164
+ else resolve(matches)
165
+ })
166
+ } catch (e) {
167
+ resolve([])
168
+ }
169
+ })
170
+ files.push(...matches)
171
+ }
172
+
173
+ return files
174
+ }
175
+
176
+ /**
177
+ * 查找文件
178
+ */
179
+ async findFiles(projectDir, pattern) {
180
+ const glob = require('glob')
181
+ return await new Promise((resolve) => {
182
+ try {
183
+ glob(pattern, {
184
+ cwd: projectDir,
185
+ ignore: ['node_modules/**', 'dist/**', 'build/**', 'vendor/**', '.git/**']
186
+ }, (err, matches) => {
187
+ resolve(err ? [] : matches)
188
+ })
189
+ } catch (e) {
190
+ resolve([])
191
+ }
192
+ })
193
+ }
194
+
195
+ /**
196
+ * 分析代码
197
+ */
198
+ async analyze(projectDir, options = {}) {
199
+ console.log(chalk.blue.bold('\n🌐 多语言代码分析'))
200
+ console.log(chalk.gray('='.repeat(70)))
201
+
202
+ const detected = await this.detectLanguage(projectDir)
203
+
204
+ if (detected.length === 0) {
205
+ console.log(chalk.yellow('⚠️ 未检测到支持的编程语言'))
206
+ return {
207
+ success: false,
208
+ message: 'No supported languages detected',
209
+ languages: []
210
+ }
211
+ }
212
+
213
+ console.log(chalk.cyan(`\n📋 检测到 ${detected.length} 种语言:`))
214
+ detected.forEach(lang => {
215
+ const confidence = lang.confidence === 'high' ? chalk.green('✓') :
216
+ lang.confidence === 'medium' ? chalk.yellow('⚠') : chalk.gray('?')
217
+ console.log(` ${confidence} ${lang.name} (${lang.confidence})`)
218
+ })
219
+
220
+ // 分析每种语言
221
+ const results = []
222
+ for (const lang of detected) {
223
+ console.log(chalk.cyan(`\n分析 ${lang.name}...`))
224
+ const result = await this.analyzeLanguage(projectDir, lang)
225
+ results.push(result)
226
+ }
227
+
228
+ return {
229
+ success: true,
230
+ languages: detected,
231
+ results
232
+ }
233
+ }
234
+
235
+ /**
236
+ * 分析特定语言
237
+ */
238
+ async analyzeLanguage(projectDir, language) {
239
+ const config = this.languageConfigs[language.key]
240
+ const files = await this.scanFiles(projectDir, config.patterns)
241
+
242
+ if (files.length === 0) {
243
+ return {
244
+ language: language.name,
245
+ files: 0,
246
+ lines: 0,
247
+ complexity: 0,
248
+ issues: []
249
+ }
250
+ }
251
+
252
+ let totalLines = 0
253
+ let totalComplexity = 0
254
+ let issues = []
255
+
256
+ // 分析前 100 个文件(避免性能问题)
257
+ const filesToAnalyze = files.slice(0, 100)
258
+
259
+ for (const file of filesToAnalyze) {
260
+ const filePath = path.join(projectDir, file)
261
+
262
+ try {
263
+ const content = await fs.readFile(filePath, 'utf8')
264
+ const lines = content.split('\n').length
265
+ totalLines += lines
266
+
267
+ // 计算复杂度
268
+ const complexity = this.calculateComplexity(content, config.complexityKeywords)
269
+ totalComplexity += complexity
270
+
271
+ // 检查代码问题
272
+ const fileIssues = this.checkCodeIssues(content, file, config)
273
+ issues.push(...fileIssues)
274
+ } catch (error) {
275
+ // 忽略无法读取的文件
276
+ }
277
+ }
278
+
279
+ const avgComplexity = filesToAnalyze.length > 0 ? totalComplexity / filesToAnalyze.length : 0
280
+
281
+ return {
282
+ language: language.name,
283
+ files: filesToAnalyze.length,
284
+ lines: totalLines,
285
+ avgComplexity: Math.round(avgComplexity),
286
+ totalComplexity,
287
+ issues: issues.slice(0, 50) // 最多显示 50 个问题
288
+ }
289
+ }
290
+
291
+ /**
292
+ * 计算复杂度
293
+ */
294
+ calculateComplexity(code, keywords) {
295
+ let complexity = 1
296
+
297
+ for (const keyword of keywords) {
298
+ const regex = new RegExp(`\\b${keyword}\\b`, 'g')
299
+ const matches = code.match(regex)
300
+ if (matches) {
301
+ complexity += matches.length
302
+ }
303
+ }
304
+
305
+ return complexity
306
+ }
307
+
308
+ /**
309
+ * 检查代码问题
310
+ */
311
+ checkCodeIssues(code, filePath, config) {
312
+ const issues = []
313
+ const lines = code.split('\n')
314
+
315
+ lines.forEach((line, index) => {
316
+ const lineNumber = index + 1
317
+
318
+ // 检查长函数(超过 100 行)
319
+ if (lineNumber === 100) {
320
+ issues.push({
321
+ file: filePath,
322
+ line: lineNumber,
323
+ severity: 'warning',
324
+ message: 'Function or file exceeds 100 lines',
325
+ type: 'complexity'
326
+ })
327
+ }
328
+
329
+ // 检查 TODO 注释
330
+ if (line.includes('TODO') || line.includes('FIXME')) {
331
+ issues.push({
332
+ file: filePath,
333
+ line: lineNumber,
334
+ severity: 'warning',
335
+ message: 'Contains TODO/FIXME comment',
336
+ type: 'documentation'
337
+ })
338
+ }
339
+
340
+ // 检查 console.log(JavaScript/TypeScript)
341
+ if (config.name.includes('JavaScript') || config.name.includes('TypeScript')) {
342
+ if (line.includes('console.log') || line.includes('console.error')) {
343
+ issues.push({
344
+ file: filePath,
345
+ line: lineNumber,
346
+ severity: 'warning',
347
+ message: 'Contains console statement',
348
+ type: 'debug'
349
+ })
350
+ }
351
+ }
352
+ })
353
+
354
+ return issues
355
+ }
356
+
357
+ /**
358
+ * 生成多语言报告
359
+ */
360
+ generateReport(analysisResult) {
361
+ const timestamp = new Date().toLocaleString()
362
+
363
+ let report = `# 多语言代码质量分析报告\n\n`
364
+ report += `**生成时间**: ${timestamp}\n\n`
365
+ report += `## 检测到的语言\n\n`
366
+
367
+ analysisResult.results.forEach(result => {
368
+ report += `### ${result.language}\n\n`
369
+ report += `- 文件数: ${result.files}\n`
370
+ report += `- 代码行数: ${result.lines}\n`
371
+ report += `- 平均复杂度: ${result.avgComplexity}\n`
372
+ report += `- 问题数: ${result.issues.length}\n\n`
373
+ })
374
+
375
+ report += `## 问题详情\n\n`
376
+
377
+ let allIssues = []
378
+ analysisResult.results.forEach(result => {
379
+ allIssues = allIssues.concat(result.issues)
380
+ })
381
+
382
+ if (allIssues.length === 0) {
383
+ report += `✅ 没有发现问题\n\n`
384
+ } else {
385
+ allIssues.forEach(issue => {
386
+ report += `- **${issue.severity.toUpperCase()}**: ${issue.message} in ${issue.file}:${issue.line}\n`
387
+ })
388
+ report += `\n`
389
+ }
390
+
391
+ report += `---\n*由 Code-Simplifier 多语言分析器生成*\n`
392
+
393
+ return report
394
+ }
395
+ }
396
+
397
+ module.exports = new MultiLanguageAnalyzer()
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "code-simplifier",
3
- "version": "1.0.0",
4
- "description": "Code-Simplifier持续改进系统 - 自动化的代码质量监控、持续改进和知识管理工具",
3
+ "version": "1.1.0",
4
+ "description": "Code-Simplifier持续改进系统 - 自动化的代码质量监控、持续改进和知识管理工具(支持 ESLint、Git 钩子、自动修复、多语言分析、完整测试套件)",
5
5
  "keywords": [
6
6
  "code-quality",
7
7
  "continuous-improvement",
@@ -9,7 +9,14 @@
9
9
  "quality-monitor",
10
10
  "best-practices",
11
11
  "code-simplification",
12
- "developer-tools"
12
+ "developer-tools",
13
+ "eslint",
14
+ "git-hooks",
15
+ "auto-fix",
16
+ "multi-language",
17
+ "testing",
18
+ "jest",
19
+ "cypress"
13
20
  ],
14
21
  "author": "Claude Code <noreply@anthropic.com>",
15
22
  "license": "MIT",
@@ -29,7 +36,9 @@
29
36
  "bin/",
30
37
  "lib/",
31
38
  "README.md",
32
- "LICENSE"
39
+ "LICENSE",
40
+ "jest.config.js",
41
+ "cypress.config.js"
33
42
  ],
34
43
  "engines": {
35
44
  "node": ">=14.0.0"
@@ -37,7 +46,13 @@
37
46
  "scripts": {
38
47
  "test": "jest",
39
48
  "test:watch": "jest --watch",
49
+ "test:unit": "jest tests/unit",
50
+ "test:integration": "jest tests/integration",
51
+ "test:e2e": "cypress run",
52
+ "test:e2e:open": "cypress open",
53
+ "test:coverage": "jest --coverage",
40
54
  "lint": "eslint bin lib",
55
+ "lint:fix": "eslint bin lib --fix",
41
56
  "prepare": "husky install || echo 'husky not installed, skipping'"
42
57
  },
43
58
  "dependencies": {
@@ -52,6 +67,7 @@
52
67
  },
53
68
  "devDependencies": {
54
69
  "jest": "^29.7.0",
70
+ "cypress": "^13.6.0",
55
71
  "eslint": "^8.57.0",
56
72
  "husky": "^8.0.3"
57
73
  },