Skip to content

refactor: 重构项目为分层架构#1

Merged
INSide-734 merged 16 commits intomasterfrom
refactor/layered-architecture
Mar 31, 2026
Merged

refactor: 重构项目为分层架构#1
INSide-734 merged 16 commits intomasterfrom
refactor/layered-architecture

Conversation

@INSide-734
Copy link
Copy Markdown
Owner

概述

将 CraftEngine VS Code 扩展从扁平结构全面重构为严格的分层架构,提升代码可维护性、可测试性和可扩展性。

架构变更

分层架构

Presentation → Application → Domain → Core ← Infrastructure
  • Core: 接口定义、类型系统、常量、错误类型、通用工具
  • Domain: 业务实体 (Template)、领域服务 (DataStoreService, TemplateService)、各类 Store
  • Application: 用例编排 (ExtensionService, SchemaService, ModelPreviewService)
  • Infrastructure: DI 容器、YAML 处理、日志、文件系统、缓存、数据加载、渲染器、配置管理
  • Presentation: VS Code 提供者、补全策略、诊断、代码操作、命令、WebView

关键设计模式

  • 依赖注入: ServiceContainer + SERVICE_TOKENS (Symbol)
  • 事件驱动: EventBus 实现跨层通信,支持通配符订阅
  • 策略模式: 补全系统使用优先级策略链
  • 依赖反转: 所有层通过 Core 层接口 (I-prefix) 通信

构建系统变更

变更项
包管理器 npm pnpm
构建工具 tsc esbuild
测试框架 Mocha Vitest
锁文件 package-lock.json pnpm-lock.yaml

CI/CD 新增工作流

  • CodeQL: 代码安全扫描
  • Security Audit: 依赖安全审计
  • TypeCheck: TypeScript 类型检查
  • Test Coverage: 测试覆盖率报告
  • Schema Validation: JSON Schema 验证
  • Benchmark: 性能基准测试
  • PR Labeler: PR 自动标签

新增功能模块

Minecraft 模型系统

  • 物品模型定义与解析 (ItemModel, ItemModelResolver)
  • 模型生成器 (ModelGenerator, AbstractModelGenerator)
  • 注册表系统 (Registry, MappedRegistry, SimpleRegistry)
  • 3D 渲染器 (MinecraftModelRenderer, Scene, Camera)
  • Worker 线程池 (WorkerPool) 用于离屏渲染

Schema 系统增强

  • 动态 Schema 生成 (SchemaDynamicGenerator)
  • Schema 引用解析 (SchemaReferenceResolver)
  • 模板展开 (TemplateExpander)
  • Schema 部署服务 (SchemaDeploymentService)

诊断与代码操作

  • 多类型诊断提供者 (Template, Translation, Schema, Category, ItemId, FilePath, MiniMessage, VersionCondition, ExtendedType)
  • 快速修复 (EnumValueFix, RequiredFieldFix, TypeMismatchFix, UnknownPropertyFix)
  • 诊断忽略解析器 (DiagnosticIgnoreParser)

数据外部化

  • 配置数据迁移到 data/ 目录 (constants, minecraft, network, schema)
  • JSON Schema 定义迁移到 schemas/ 目录

测试

  • 60+ 单元测试文件覆盖所有层
  • 基准测试 (DI 容器、EventBus、Schema、Template、YAML 解析器)
  • Vitest + VS Code mock 测试基础设施

变更统计

  • 613 个文件变更
  • 110,001 行新增 / 8,922 行删除

检查清单

  • 分层架构依赖规则正确 (内层不依赖外层)
  • 所有接口定义在 Core 层
  • DI 容器正确注册所有服务
  • 事件系统正确连接
  • 单元测试覆盖
  • CI/CD 工作流配置

将整个项目从扁平结构重构为严格的分层架构 (Presentation → Application → Domain → Core ← Infrastructure),
涵盖以下主要变更:

## 架构重构
- 引入分层架构:Core / Domain / Application / Infrastructure / Presentation
- 实现依赖注入容器 (ServiceContainer) 和服务令牌 (SERVICE_TOKENS)
- 引入 EventBus 事件总线实现跨层通信
- 统一使用接口 (I-prefix) 进行依赖反转

## 构建系统
- 从 npm 迁移到 pnpm
- 引入 esbuild 替代 tsc 进行生产构建
- 引入 Vitest 替代原有测试框架
- 新增 CI/CD 工作流 (CodeQL, 安全审计, 类型检查, 测试覆盖率, Schema 验证, 基准测试)

## 核心层 (Core)
- 定义所有接口 (ITemplateService, ISchemaService, ILogger 等)
- 定义类型系统 (ConfigTypes, DomainEvents, EditorTypes, JsonSchemaTypes 等)
- 定义常量 (DiagnosticCodes, ServiceTokens, ExtensionConstants)
- 定义错误类型 (ExtensionErrors)
- 通用工具 (LRUCache, Debouncer, AsyncInitializer, IdGenerator)

## 领域层 (Domain)
- Template 实体和值对象
- DataStoreService 统一存储服务
- TemplateService 模板业务逻辑
- 各类 Store (CategoryStore, ItemStore, TemplateStore, TranslationStore 等)
- MiniMessage 解析器
- Minecraft 物品模型系统 (ItemModel, ModelGenerator, Registry 等)

## 应用层 (Application)
- ExtensionService 扩展生命周期管理
- SchemaService 及其子服务 (SchemaCache, SchemaLoader, SchemaDynamicGenerator 等)
- ModelPreviewService 模型预览服务
- 扩展子服务 (DataCacheInitializer, DocumentChangeTracker, WorkspaceDiagnosticManager 等)

## 基础设施层 (Infrastructure)
- DI 容器和注册器 (DependencyContainer, ApplicationRegistrar, DomainRegistrar 等)
- YAML 处理 (YamlParser, YamlPathParser, YamlScanner)
- 日志系统 (Logger, FileLogTarget, OutputChannelLogTarget)
- 文件系统 (FileWatcher, NamespaceDiscoveryService, ResourcePackDiscovery)
- 缓存系统 (DiagnosticCache, DocumentParseCache, IncrementalAnalyzer)
- 数据加载 (MinecraftDataService, MinecraftVersionService, DataConfigLoader)
- 渲染器 (MinecraftModelRenderer, WorkerPool, Scene, Camera)
- Schema 验证 (SchemaLoader, SchemaValidator)
- 配置管理 (ConfigurationManager, DiagnosticSeverityConfig)
- 性能监控 (PerformanceMonitor)

## 表现层 (Presentation)
- 统一补全系统 (UnifiedCompletionProvider, CompletionManager)
- 策略模式补全 (SchemaAwareCompletionStrategy, 各类 DelegateStrategy)
- 诊断提供者 (Template, Translation, Schema, Category, ItemId, FilePath 等)
- 代码操作提供者 (QuickFix: EnumValueFix, RequiredFieldFix, TypeMismatchFix 等)
- 定义跳转 (CategoryDefinitionProvider, ItemIdDefinitionProvider, TemplateDefinitionProvider)
- 悬停提示 (SchemaKeyHoverProvider, TemplateHoverProvider)
- WebView 模型预览 (ModelPreviewPanel)
- 命令注册 (ModelPreviewCommands, SchemaCommands, NewTemplateCommands)

## 数据与配置
- 外部化配置数据到 data/ 目录 (constants, minecraft, network, schema)
- JSON Schema 定义到 schemas/ 目录
- 新增 Minecraft 模型属性和版本数据

## 测试
- 全面的单元测试覆盖 (60+ 测试文件)
- 基准测试 (DI 容器, EventBus, Schema, Template, YAML 解析器)
- Vitest 配置和 VS Code mock
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 19, 2026

📊 Test Coverage Report

Metric Coverage Status
Lines 37.33% ⚠️
Branches 33.55% ⚠️
Functions 41.64% ⚠️
Statements 37.43% ⚠️

⚠️ Coverage below threshold (<80%)

@github-advanced-security
Copy link
Copy Markdown

This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation.

Comment thread src/application/services/schema/SchemaFileLoader.ts Fixed
Comment thread src/infrastructure/data/DataConfigLoader.ts Fixed
Comment thread src/application/services/schema/SchemaPathNavigator.ts Fixed
Comment thread src/infrastructure/renderer/scene/geometry/rectangle/Rectangle.ts Fixed
Comment thread src/presentation/providers/helpers/SchemaDiagnosticFormatter.ts Fixed
Comment thread src/test/benchmark/event-bus.bench.ts Fixed
Comment thread src/test/benchmark/translation-store.bench.ts Fixed
Comment thread src/infrastructure/di/registrars/DomainRegistrar.ts Fixed
- 修复 translations.schema.json 的 $id 域名不一致问题
  (craftengine.xiao-momi.com → craftengine.dev)
- 修改 ajv 验证步骤,加载所有引用的 schema 文件 (-r 参数)
  以支持跨文件 $ref 解析
- 移除冗余条件检查 (js/trivial-conditional)
- 修复重复操作 (js/redundant-operation)
- 消费无效表达式结果 (js/useless-expression)
- 修复正则表达式字符类中的重复字符 (js/regex/duplicate-in-character-class)
- 移除未使用的导入和变量 (js/unused-local-variable)
- 修复构造函数属性覆盖 (js/useless-assignment-to-property)
- 消除文件系统竞态条件 (js/file-system-race)
- 添加 CodeQL 配置排除 scripts 目录 (js/file-access-to-http)
master 分支缺少 pnpm-lock.yaml,导致 --frozen-lockfile 失败,
改用 --no-frozen-lockfile 安装 base 分支依赖。
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 19, 2026

⚡ Benchmark Results

No benchmark results to compare.

✅ No significant performance regression

移除 package job 的事件类型限制,使 VSIX 打包和 artifact 上传在所有触发事件(push、PR、workflow_dispatch)中都执行,便于在 PR 阶段验证打包流程。
@github-actions
Copy link
Copy Markdown

🔒 Security Audit Report

Severity Count
🔴 Critical 0
🟠 High 4
🟡 Moderate 2
🟢 Low 1
Total 7

Run pnpm audit locally for details.

package script 仅执行了 esbuild 编译,未调用 vsce package 生成 .vsix 文件,
导致 CI 中 upload-artifact 找不到 .vsix 文件。
CI 环境中 vsce 命令不可用,将 @vscode/vsce 加入 devDependencies,
并将 script 中的裸 vsce 调用改为 pnpm exec vsce。
将 vscode:prepublish 改为只执行编译(clean + esbuild --production),
package script 改为只调用 vsce package,由 vsce 自动触发 prepublish 完成编译,
避免 package → vsce package → prepublish → package 的循环调用。
vsce 内部调用 npm list --production 检查依赖树,
与 pnpm 的 node_modules 结构不兼容。
添加 --no-dependencies 跳过检查,esbuild 已将依赖打包进 bundle。
- 升级 ajv 8.17.1 → 8.18.0(修复 ReDoS)
- 升级 glob 11.1.0 → 13.0.6(修复 minimatch ReDoS)
- 添加 pnpm overrides 修复间接依赖漏洞:
  minimatch、@isaacs/brace-expansion、diff
- 剩余 1 个 moderate(eslint 内部 ajv@6,上游问题)
@github-actions
Copy link
Copy Markdown

🔒 Security Audit Report

Severity Count
🔴 Critical 0
🟠 High 0
🟡 Moderate 1
🟢 Low 0
Total 1

Run pnpm audit locally for details.

Repository owner deleted a comment from github-actions Bot Feb 20, 2026
Repository owner deleted a comment from github-actions Bot Feb 20, 2026
Repository owner deleted a comment from github-actions Bot Feb 20, 2026
Repository owner deleted a comment from github-actions Bot Feb 20, 2026
minimatch@<10.2.1 的 override 将 vsce 依赖的 minimatch@^3 (CJS)
强制升级到 v10+ (ESM-only),导致 CJS require() 调用失败
@github-actions
Copy link
Copy Markdown

🔒 Security Audit Report

Severity Count
🔴 Critical 0
🟠 High 2
🟡 Moderate 1
🟢 Low 0
Total 3

Run pnpm audit locally for details.

…ture schema services

- Add prettier, eslint-config-prettier, editorconfig and format CI check
- Enhance eslint config with stricter type-safety rules
- Rewrite README with modern layout and badges
- Add core interfaces: IExtensionRegistry, IFileWatcherFactory, INotificationService, ISchemaFileLoader
- Add SafeRegex utility for safe regex compilation
- Add infrastructure implementations: VscodeExtensionRegistry, NotificationService, VscodeFileWatcherFactory
- Move SchemaFileLoader from application to infrastructure layer
- Remove SchemaDeploymentService (responsibilities redistributed)
- Register new services in DI container
- Cache compiled version condition regex pattern
- Use ISchemaFileLoader interface in SchemaLoaderService
… layers

- Core: ExtensionErrors, AsyncInitializer, Debouncer, deepFreeze, LRUCache, SafeRegex, StringSimilarityUtils
- Domain: ExtendedTypeService, DataStoreStatisticsCollector, DocumentProcessor, TemplateSearchService, TemplateSuggestionService, TemplateUsageService
- Infrastructure: DiagnosticCache, IncrementalAnalyzer, CompositeSubscription, PerformanceMonitor, SchemaFileLoader, SchemaTransformer, ValidationErrorFormatter, YamlDocument, YamlHelper
- Application: DocumentChangeTracker, YamlExtensionIntegrator
@github-actions
Copy link
Copy Markdown

🔒 Security Audit Report

Severity Count
🔴 Critical 0
🟠 High 2
🟡 Moderate 1
🟢 Low 0
Total 3

Run pnpm audit locally for details.

Comment thread src/test/unit/domain/services/template/TemplateUsageService.test.ts Fixed
Comment thread src/test/unit/infrastructure/performance/PerformanceMonitor.test.ts Fixed
Comment thread src/test/unit/infrastructure/yaml/YamlDocument.test.ts Fixed
Consolidate all changes since v0.0.3 into the CHANGELOG entry, including
build pipeline fixes, CI improvements, Prettier toolchain, sub-module
extractions, security fixes, and new unit tests.
@github-actions
Copy link
Copy Markdown

🔒 Security Audit Report

Severity Count
🔴 Critical 0
🟠 High 17
🟡 Moderate 11
🟢 Low 0
Total 28

Run pnpm audit locally for details.

Comment thread esbuild.config.mjs
export const createBuildConfig = (options = {}) => {
const {
production = false,
watch = false,

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused variable watch.

Copilot Autofix

AI 28 days ago

In general, to fix unused variable issues, either remove the unused binding or start using it meaningfully. Here the simplest fix that does not change existing behavior is to stop destructuring watch from options, since it is never read. That preserves the current semantics (the function still ignores any watch option the caller may pass) while eliminating the unused variable warning.

Concretely, in esbuild.config.mjs, inside createBuildConfig, edit the destructuring at lines 21–25 to remove watch. The rest of the function, including production and sourcemap, remains unchanged. No imports, methods, or additional definitions are needed.

Suggested changeset 1
esbuild.config.mjs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/esbuild.config.mjs b/esbuild.config.mjs
--- a/esbuild.config.mjs
+++ b/esbuild.config.mjs
@@ -20,7 +20,6 @@
 export const createBuildConfig = (options = {}) => {
   const {
     production = false,
-    watch = false,
     sourcemap = !production ? 'inline' : 'external',
   } = options;
 
EOF
@@ -20,7 +20,6 @@
export const createBuildConfig = (options = {}) => {
const {
production = false,
watch = false,
sourcemap = !production ? 'inline' : 'external',
} = options;

Copilot is powered by AI and may make mistakes. Always verify output.
Comment thread esbuild.mjs
import { copy } from 'esbuild-plugin-copy';
import { cpSync, mkdirSync, existsSync, readdirSync, readFileSync } from 'fs';
import { execSync } from 'child_process';
import { resolve, dirname, join } from 'path';

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused import resolve.

Copilot Autofix

AI 28 days ago

In general, unused imports should be removed from the import list so that only actually used symbols are imported. This keeps the codebase cleaner and avoids confusion about whether an unused symbol is part of some incomplete implementation.

For this specific case, in esbuild.mjs on line 5, the named import list from 'path' includes resolve, dirname, and join. Only dirname and join are used (at lines 16 and 131 respectively). The best fix that does not alter any runtime behavior is to remove resolve from this destructuring import while leaving dirname and join intact. No additional code changes or imports are needed, and no logic elsewhere needs to be updated as a result.

Concretely:

  • Edit esbuild.mjs.
  • Locate the line import { resolve, dirname, join } from 'path';.
  • Change it to import { dirname, join } from 'path';.
Suggested changeset 1
esbuild.mjs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/esbuild.mjs b/esbuild.mjs
--- a/esbuild.mjs
+++ b/esbuild.mjs
@@ -2,7 +2,7 @@
 import { copy } from 'esbuild-plugin-copy';
 import { cpSync, mkdirSync, existsSync, readdirSync, readFileSync } from 'fs';
 import { execSync } from 'child_process';
-import { resolve, dirname, join } from 'path';
+import { dirname, join } from 'path';
 import { fileURLToPath } from 'url';
 import { createBuildConfig, paths } from './esbuild.config.mjs';
 import { logger } from './scripts/logger.js';
EOF
@@ -2,7 +2,7 @@
import { copy } from 'esbuild-plugin-copy';
import { cpSync, mkdirSync, existsSync, readdirSync, readFileSync } from 'fs';
import { execSync } from 'child_process';
import { resolve, dirname, join } from 'path';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
import { createBuildConfig, paths } from './esbuild.config.mjs';
import { logger } from './scripts/logger.js';
Copilot is powered by AI and may make mistakes. Always verify output.
Comment thread esbuild.mjs
import { execSync } from 'child_process';
import { resolve, dirname, join } from 'path';
import { fileURLToPath } from 'url';
import { createBuildConfig, paths } from './esbuild.config.mjs';

Check notice

Code scanning / CodeQL

Unused variable, import, function or class Note

Unused import createBuildConfig.

Copilot Autofix

AI 28 days ago

To fix the problem, remove the unused named import createBuildConfig and keep only paths from ./esbuild.config.mjs. This eliminates the unused binding while preserving all existing functionality, since module side effects are preserved as long as the module is imported at least once (which it still will be, via paths).

Concretely, in esbuild.mjs, at the import on line 7, change:

import { createBuildConfig, paths } from './esbuild.config.mjs';

to:

import { paths } from './esbuild.config.mjs';

No additional methods, imports, or definitions are required; we are only removing an unused symbol from an existing import.

Suggested changeset 1
esbuild.mjs

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/esbuild.mjs b/esbuild.mjs
--- a/esbuild.mjs
+++ b/esbuild.mjs
@@ -4,7 +4,7 @@
 import { execSync } from 'child_process';
 import { resolve, dirname, join } from 'path';
 import { fileURLToPath } from 'url';
-import { createBuildConfig, paths } from './esbuild.config.mjs';
+import { paths } from './esbuild.config.mjs';
 import { logger } from './scripts/logger.js';
 import {
   shouldCopyDependencies,
EOF
@@ -4,7 +4,7 @@
import { execSync } from 'child_process';
import { resolve, dirname, join } from 'path';
import { fileURLToPath } from 'url';
import { createBuildConfig, paths } from './esbuild.config.mjs';
import { paths } from './esbuild.config.mjs';
import { logger } from './scripts/logger.js';
import {
shouldCopyDependencies,
Copilot is powered by AI and may make mistakes. Always verify output.
- Upgrade yaml to ^2.8.3 and add security overrides for minimatch,
  rollup, serialize-javascript, flatted, undici, picomatch, ajv,
  brace-expansion
- Apply prettier formatting across source and test files
- Fix Debouncer to use console.error instead of rethrowing when
  no logger is available
- Fix async test assertions with vi.waitFor and
  vi.advanceTimersByTimeAsync
- Exclude interface and type-only files from coverage reports
@INSide-734 INSide-734 merged commit 6a13d74 into master Mar 31, 2026
13 checks passed
@INSide-734 INSide-734 deleted the refactor/layered-architecture branch April 1, 2026 01:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants