autosnippet 3.3.6 → 3.3.8
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/README.md +1 -0
- package/dashboard/dist/assets/icons-BMNb0V6L.js +1 -0
- package/dashboard/dist/assets/index-DHJ1Dj7u.css +1 -0
- package/dashboard/dist/assets/index-DV8biUkH.js +112 -0
- package/dashboard/dist/index.html +3 -3
- package/dist/bin/cli.js +8 -4
- package/dist/lib/agent/AgentRuntime.d.ts +2 -2
- package/dist/lib/agent/AgentRuntime.js +26 -18
- package/dist/lib/agent/core/ChatAgentPrompts.js +57 -21
- package/dist/lib/agent/core/LoopContext.d.ts +1 -0
- package/dist/lib/agent/core/ToolExecutionPipeline.js +13 -0
- package/dist/lib/agent/domain/ChatAgentTasks.js +4 -0
- package/dist/lib/agent/forced-summary.js +7 -2
- package/dist/lib/agent/memory/ActiveContext.d.ts +0 -2
- package/dist/lib/agent/memory/ActiveContext.js +0 -2
- package/dist/lib/agent/memory/MemoryEmbeddingStore.d.ts +49 -0
- package/dist/lib/agent/memory/MemoryEmbeddingStore.js +159 -0
- package/dist/lib/agent/memory/MemoryRetriever.d.ts +2 -0
- package/dist/lib/agent/memory/MemoryRetriever.js +25 -11
- package/dist/lib/agent/memory/MemoryStore.d.ts +8 -41
- package/dist/lib/agent/memory/MemoryStore.js +196 -261
- package/dist/lib/agent/memory/PersistentMemory.d.ts +2 -0
- package/dist/lib/agent/memory/PersistentMemory.js +4 -5
- package/dist/lib/agent/memory/SessionStore.d.ts +0 -2
- package/dist/lib/agent/memory/SessionStore.js +0 -2
- package/dist/lib/agent/tools/ast-graph.js +21 -19
- package/dist/lib/agent/tools/infrastructure.js +3 -2
- package/dist/lib/agent/tools/project-access.d.ts +2 -2
- package/dist/lib/agent/tools/project-access.js +5 -4
- package/dist/lib/bootstrap.js +2 -1
- package/dist/lib/cli/AiScanService.js +8 -21
- package/dist/lib/cli/KnowledgeSyncService.d.ts +7 -37
- package/dist/lib/cli/KnowledgeSyncService.js +23 -51
- package/dist/lib/core/ast/ProjectGraph.js +5 -27
- package/dist/lib/core/discovery/ConfigWatcher.d.ts +64 -0
- package/dist/lib/core/discovery/ConfigWatcher.js +336 -0
- package/dist/lib/core/discovery/CustomConfigDiscoverer.d.ts +28 -0
- package/dist/lib/core/discovery/CustomConfigDiscoverer.js +1303 -0
- package/dist/lib/core/discovery/DiscovererPreference.d.ts +44 -0
- package/dist/lib/core/discovery/DiscovererPreference.js +141 -0
- package/dist/lib/core/discovery/DiscovererRegistry.d.ts +10 -1
- package/dist/lib/core/discovery/DiscovererRegistry.js +42 -2
- package/dist/lib/core/discovery/ProjectDiscoverer.d.ts +19 -0
- package/dist/lib/core/discovery/index.d.ts +2 -0
- package/dist/lib/core/discovery/index.js +4 -0
- package/dist/lib/core/discovery/parsers/CMakeParser.d.ts +32 -0
- package/dist/lib/core/discovery/parsers/CMakeParser.js +148 -0
- package/dist/lib/core/discovery/parsers/GradleDslParser.d.ts +43 -0
- package/dist/lib/core/discovery/parsers/GradleDslParser.js +171 -0
- package/dist/lib/core/discovery/parsers/JsonConfigParser.d.ts +45 -0
- package/dist/lib/core/discovery/parsers/JsonConfigParser.js +122 -0
- package/dist/lib/core/discovery/parsers/RubyDslParser.d.ts +49 -0
- package/dist/lib/core/discovery/parsers/RubyDslParser.js +282 -0
- package/dist/lib/core/discovery/parsers/StarlarkParser.d.ts +33 -0
- package/dist/lib/core/discovery/parsers/StarlarkParser.js +229 -0
- package/dist/lib/core/discovery/parsers/YamlConfigParser.d.ts +37 -0
- package/dist/lib/core/discovery/parsers/YamlConfigParser.js +212 -0
- package/dist/lib/domain/dimension/DimensionRegistry.d.ts +0 -2
- package/dist/lib/domain/dimension/DimensionRegistry.js +0 -2
- package/dist/lib/domain/dimension/DimensionSop.js +44 -33
- package/dist/lib/domain/dimension/UnifiedDimension.d.ts +0 -2
- package/dist/lib/domain/dimension/UnifiedDimension.js +0 -2
- package/dist/lib/domain/knowledge/KnowledgeEntry.d.ts +7 -1
- package/dist/lib/domain/knowledge/KnowledgeEntry.js +17 -3
- package/dist/lib/domain/knowledge/Lifecycle.d.ts +26 -0
- package/dist/lib/domain/knowledge/Lifecycle.js +42 -0
- package/dist/lib/domain/knowledge/index.d.ts +2 -1
- package/dist/lib/domain/knowledge/index.js +1 -1
- package/dist/lib/external/ai/AiProvider.d.ts +12 -0
- package/dist/lib/external/ai/AiProvider.js +24 -0
- package/dist/lib/external/ai/AiProviderManager.d.ts +101 -0
- package/dist/lib/external/ai/AiProviderManager.js +193 -0
- package/dist/lib/external/ai/providers/ClaudeProvider.js +11 -0
- package/dist/lib/external/ai/providers/GoogleGeminiProvider.js +18 -0
- package/dist/lib/external/ai/providers/MockProvider.d.ts +21 -3
- package/dist/lib/external/ai/providers/MockProvider.js +290 -14
- package/dist/lib/external/ai/providers/OpenAiProvider.js +16 -0
- package/dist/lib/external/lark/LarkTransport.d.ts +5 -1
- package/dist/lib/external/lark/LarkTransport.js +10 -2
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.d.ts +2 -1
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +102 -153
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.d.ts +20 -0
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/mock-pipeline.js +432 -0
- package/dist/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +49 -24
- package/dist/lib/external/mcp/handlers/bootstrap/refine.js +8 -0
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.d.ts +1 -1
- package/dist/lib/external/mcp/handlers/bootstrap/shared/bootstrap-phases.js +41 -37
- package/dist/lib/external/mcp/handlers/bootstrap-external.d.ts +9 -0
- package/dist/lib/external/mcp/handlers/bootstrap-external.js +3 -1
- package/dist/lib/external/mcp/handlers/bootstrap-internal.js +2 -0
- package/dist/lib/external/mcp/handlers/consolidated.js +2 -1
- package/dist/lib/external/mcp/handlers/dimension-complete-external.js +9 -4
- package/dist/lib/external/mcp/handlers/evolve-external.d.ts +1 -0
- package/dist/lib/external/mcp/handlers/evolve-external.js +18 -18
- package/dist/lib/external/mcp/handlers/guard.js +15 -24
- package/dist/lib/external/mcp/handlers/knowledge.js +5 -4
- package/dist/lib/external/mcp/handlers/panorama.js +9 -9
- package/dist/lib/external/mcp/handlers/rescan-external.js +7 -6
- package/dist/lib/external/mcp/handlers/rescan-internal.js +9 -5
- package/dist/lib/external/mcp/handlers/search.js +3 -1
- package/dist/lib/external/mcp/handlers/skill.js +4 -4
- package/dist/lib/external/mcp/handlers/structure.js +8 -12
- package/dist/lib/external/mcp/handlers/system.js +10 -34
- package/dist/lib/http/routes/ai.js +109 -30
- package/dist/lib/http/routes/candidates.js +11 -4
- package/dist/lib/http/routes/commands.js +10 -1
- package/dist/lib/http/routes/guardReport.js +3 -5
- package/dist/lib/http/routes/health.js +11 -0
- package/dist/lib/http/routes/modules.js +27 -0
- package/dist/lib/http/routes/panorama.js +12 -12
- package/dist/lib/http/routes/recipes.js +66 -8
- package/dist/lib/http/routes/remote.js +3 -13
- package/dist/lib/http/routes/search.js +11 -8
- package/dist/lib/http/utils/routeHelpers.js +2 -1
- package/dist/lib/infrastructure/audit/AuditLogger.d.ts +20 -3
- package/dist/lib/infrastructure/audit/AuditStore.d.ts +28 -29
- package/dist/lib/infrastructure/audit/AuditStore.js +81 -88
- package/dist/lib/infrastructure/database/drizzle/schema.d.ts +180 -2
- package/dist/lib/infrastructure/database/drizzle/schema.js +23 -3
- package/dist/lib/injection/ServiceContainer.d.ts +6 -5
- package/dist/lib/injection/ServiceContainer.js +18 -31
- package/dist/lib/injection/ServiceMap.d.ts +22 -0
- package/dist/lib/injection/modules/AiModule.d.ts +6 -9
- package/dist/lib/injection/modules/AiModule.js +82 -39
- package/dist/lib/injection/modules/AppModule.js +2 -1
- package/dist/lib/injection/modules/GuardModule.js +5 -5
- package/dist/lib/injection/modules/InfraModule.js +60 -0
- package/dist/lib/injection/modules/KnowledgeModule.js +86 -51
- package/dist/lib/injection/modules/PanoramaModule.js +16 -10
- package/dist/lib/injection/modules/VectorModule.js +3 -0
- package/dist/lib/repository/audit/AuditRepository.d.ts +107 -0
- package/dist/lib/repository/audit/AuditRepository.js +272 -0
- package/dist/lib/repository/base/RepositoryBase.d.ts +46 -0
- package/dist/lib/repository/base/RepositoryBase.js +32 -0
- package/dist/lib/repository/bootstrap/BootstrapRepository.d.ts +94 -0
- package/dist/lib/repository/bootstrap/BootstrapRepository.js +246 -0
- package/dist/lib/repository/code/CodeEntityRepository.d.ts +91 -0
- package/dist/lib/repository/code/CodeEntityRepository.js +361 -0
- package/dist/lib/repository/delivery/DeliveryRepoAdapter.d.ts +39 -0
- package/dist/lib/repository/delivery/DeliveryRepoAdapter.js +23 -0
- package/dist/lib/repository/evolution/LifecycleEventRepository.d.ts +51 -0
- package/dist/lib/repository/evolution/LifecycleEventRepository.js +119 -0
- package/dist/lib/repository/evolution/ProposalRepository.d.ts +9 -12
- package/dist/lib/repository/evolution/ProposalRepository.js +114 -57
- package/dist/lib/repository/guard/GuardViolationRepository.d.ts +104 -0
- package/dist/lib/repository/guard/GuardViolationRepository.js +217 -0
- package/dist/lib/repository/knowledge/KnowledgeEdgeRepository.d.ts +129 -0
- package/dist/lib/repository/knowledge/KnowledgeEdgeRepository.js +475 -0
- package/dist/lib/repository/knowledge/KnowledgeFileStore.d.ts +39 -0
- package/dist/lib/repository/knowledge/KnowledgeFileStore.js +12 -0
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.d.ts +295 -11
- package/dist/lib/repository/knowledge/KnowledgeRepository.impl.js +608 -13
- package/dist/lib/repository/knowledge/KnowledgeUnitOfWork.d.ts +61 -0
- package/dist/lib/repository/knowledge/KnowledgeUnitOfWork.js +156 -0
- package/dist/lib/repository/memory/MemoryRepository.d.ts +90 -0
- package/dist/lib/repository/memory/MemoryRepository.js +260 -0
- package/dist/lib/repository/search/SearchRepoAdapter.d.ts +92 -0
- package/dist/lib/repository/search/SearchRepoAdapter.js +124 -0
- package/dist/lib/repository/session/SessionRepository.d.ts +46 -0
- package/dist/lib/repository/session/SessionRepository.js +110 -0
- package/dist/lib/repository/sourceref/RecipeSourceRefRepository.d.ts +66 -0
- package/dist/lib/repository/sourceref/RecipeSourceRefRepository.js +182 -0
- package/dist/lib/repository/sync/SyncRepoAdapter.d.ts +58 -0
- package/dist/lib/repository/sync/SyncRepoAdapter.js +58 -0
- package/dist/lib/service/bootstrap/UiStartupTasks.js +5 -6
- package/dist/lib/service/bootstrap/bootstrap-event-types.d.ts +0 -1
- package/dist/lib/service/bootstrap/bootstrap-event-types.js +0 -1
- package/dist/lib/service/cleanup/CleanupService.d.ts +54 -7
- package/dist/lib/service/cleanup/CleanupService.js +291 -40
- package/dist/lib/service/delivery/CursorDeliveryPipeline.js +6 -8
- package/dist/lib/service/evolution/ConsolidationAdvisor.d.ts +4 -9
- package/dist/lib/service/evolution/ConsolidationAdvisor.js +34 -70
- package/dist/lib/service/evolution/ContentPatcher.d.ts +4 -12
- package/dist/lib/service/evolution/ContentPatcher.js +48 -19
- package/dist/lib/service/evolution/ContradictionDetector.d.ts +3 -7
- package/dist/lib/service/evolution/ContradictionDetector.js +17 -24
- package/dist/lib/service/evolution/DecayDetector.d.ts +10 -9
- package/dist/lib/service/evolution/DecayDetector.js +63 -57
- package/dist/lib/service/evolution/EnhancementSuggester.d.ts +3 -9
- package/dist/lib/service/evolution/EnhancementSuggester.js +42 -86
- package/dist/lib/service/evolution/KnowledgeMetabolism.d.ts +4 -4
- package/dist/lib/service/evolution/KnowledgeMetabolism.js +102 -71
- package/dist/lib/service/evolution/ProposalExecutor.d.ts +5 -12
- package/dist/lib/service/evolution/ProposalExecutor.js +64 -69
- package/dist/lib/service/evolution/RecipeLifecycleSupervisor.d.ts +9 -14
- package/dist/lib/service/evolution/RecipeLifecycleSupervisor.js +94 -155
- package/dist/lib/service/evolution/RecipeRelevanceAuditor.d.ts +4 -1
- package/dist/lib/service/evolution/RecipeRelevanceAuditor.js +50 -49
- package/dist/lib/service/evolution/RedundancyAnalyzer.d.ts +3 -7
- package/dist/lib/service/evolution/RedundancyAnalyzer.js +15 -22
- package/dist/lib/service/evolution/StagingManager.d.ts +6 -15
- package/dist/lib/service/evolution/StagingManager.js +37 -95
- package/dist/lib/service/evolution/createSupersedeProposal.d.ts +1 -1
- package/dist/lib/service/evolution/createSupersedeProposal.js +7 -8
- package/dist/lib/service/guard/CoverageAnalyzer.d.ts +3 -7
- package/dist/lib/service/guard/CoverageAnalyzer.js +9 -11
- package/dist/lib/service/guard/GuardCheckEngine.d.ts +3 -0
- package/dist/lib/service/guard/GuardCheckEngine.js +14 -22
- package/dist/lib/service/guard/ReverseGuard.d.ts +4 -7
- package/dist/lib/service/guard/ReverseGuard.js +21 -31
- package/dist/lib/service/guard/ViolationsStore.d.ts +15 -21
- package/dist/lib/service/guard/ViolationsStore.js +75 -69
- package/dist/lib/service/knowledge/CodeEntityGraph.d.ts +45 -63
- package/dist/lib/service/knowledge/CodeEntityGraph.js +418 -496
- package/dist/lib/service/knowledge/ConfidenceRouter.js +18 -9
- package/dist/lib/service/knowledge/KnowledgeFileWriter.d.ts +2 -1
- package/dist/lib/service/knowledge/KnowledgeGraphService.d.ts +18 -60
- package/dist/lib/service/knowledge/KnowledgeGraphService.js +58 -109
- package/dist/lib/service/knowledge/KnowledgeService.d.ts +15 -1
- package/dist/lib/service/knowledge/KnowledgeService.js +97 -46
- package/dist/lib/service/knowledge/RecipeProductionGateway.d.ts +0 -2
- package/dist/lib/service/knowledge/RecipeProductionGateway.js +0 -2
- package/dist/lib/service/knowledge/SourceRefReconciler.d.ts +5 -13
- package/dist/lib/service/knowledge/SourceRefReconciler.js +58 -78
- package/dist/lib/service/module/ModuleService.js +10 -19
- package/dist/lib/service/panorama/CouplingAnalyzer.d.ts +14 -3
- package/dist/lib/service/panorama/CouplingAnalyzer.js +137 -32
- package/dist/lib/service/panorama/DimensionAnalyzer.d.ts +7 -4
- package/dist/lib/service/panorama/DimensionAnalyzer.js +94 -33
- package/dist/lib/service/panorama/LayerInferrer.d.ts +16 -1
- package/dist/lib/service/panorama/LayerInferrer.js +118 -1
- package/dist/lib/service/panorama/ModuleDiscoverer.d.ts +14 -4
- package/dist/lib/service/panorama/ModuleDiscoverer.js +209 -61
- package/dist/lib/service/panorama/PanoramaAggregator.d.ts +15 -4
- package/dist/lib/service/panorama/PanoramaAggregator.js +128 -62
- package/dist/lib/service/panorama/PanoramaScanner.d.ts +5 -1
- package/dist/lib/service/panorama/PanoramaScanner.js +60 -31
- package/dist/lib/service/panorama/PanoramaService.d.ts +11 -8
- package/dist/lib/service/panorama/PanoramaService.js +49 -69
- package/dist/lib/service/panorama/PanoramaTypes.d.ts +41 -0
- package/dist/lib/service/panorama/RoleRefiner.d.ts +10 -5
- package/dist/lib/service/panorama/RoleRefiner.js +92 -282
- package/dist/lib/service/panorama/TechStackProfiler.d.ts +13 -0
- package/dist/lib/service/panorama/TechStackProfiler.js +79 -0
- package/dist/lib/service/quality/QualityScorer.d.ts +45 -26
- package/dist/lib/service/quality/QualityScorer.js +157 -83
- package/dist/lib/service/search/SearchEngine.d.ts +1 -0
- package/dist/lib/service/search/SearchEngine.js +32 -37
- package/dist/lib/service/signal/HitRecorder.js +5 -5
- package/dist/lib/service/skills/RuleRecallStrategy.js +7 -3
- package/dist/lib/service/skills/SignalCollector.d.ts +6 -8
- package/dist/lib/service/skills/SignalCollector.js +34 -60
- package/dist/lib/service/skills/SkillAdvisor.d.ts +7 -13
- package/dist/lib/service/skills/SkillAdvisor.js +30 -79
- package/dist/lib/service/vector/ContextualEnricher.d.ts +1 -0
- package/dist/lib/service/vector/ContextualEnricher.js +4 -0
- package/dist/lib/service/vector/SyncCoordinator.d.ts +3 -1
- package/dist/lib/service/vector/SyncCoordinator.js +25 -3
- package/dist/lib/service/vector/VectorService.d.ts +2 -0
- package/dist/lib/service/vector/VectorService.js +3 -0
- package/dist/lib/service/wiki/WikiGenerator.js +1 -1
- package/dist/lib/shared/LanguageProfiles.d.ts +109 -0
- package/dist/lib/shared/LanguageProfiles.js +939 -0
- package/dist/lib/shared/LanguageService.d.ts +6 -0
- package/dist/lib/shared/LanguageService.js +19 -0
- package/dist/lib/shared/constants.d.ts +19 -19
- package/dist/lib/shared/constants.js +10 -10
- package/dist/lib/shared/developer-identity.d.ts +18 -0
- package/dist/lib/shared/developer-identity.js +62 -0
- package/dist/lib/shared/schemas/http-requests.d.ts +8 -17
- package/dist/lib/shared/schemas/http-requests.js +9 -6
- package/dist/lib/shared/schemas/mcp-tools.d.ts +1 -1
- package/dist/lib/types/knowledge-wire.d.ts +1 -0
- package/dist/lib/types/project-snapshot-builder.d.ts +0 -1
- package/dist/lib/types/project-snapshot-builder.js +0 -1
- package/dist/lib/types/project-snapshot.d.ts +0 -1
- package/dist/lib/types/project-snapshot.js +0 -1
- package/dist/lib/types/snapshot-views.d.ts +0 -2
- package/dist/lib/types/snapshot-views.js +0 -1
- package/package.json +2 -1
- package/dashboard/dist/assets/icons-D1aVZYFW.js +0 -1
- package/dashboard/dist/assets/index-CxHOu8Hd.css +0 -1
- package/dashboard/dist/assets/index-DDdAOpYT.js +0 -128
- package/dist/lib/repository/base/BaseRepository.d.ts +0 -53
- package/dist/lib/repository/base/BaseRepository.js +0 -226
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module GradleDslParser
|
|
3
|
+
* @description Gradle DSL 轻量解析器 — 从 settings.gradle.kts / build.gradle.kts 提取项目拓扑
|
|
4
|
+
*
|
|
5
|
+
* 支持解析:
|
|
6
|
+
* - settings.gradle.kts: rootProject.name + include() 模块声明
|
|
7
|
+
* - build.gradle.kts: plugins {} + dependencies {} (project-to-project)
|
|
8
|
+
* - settings.gradle (Groovy 语法)
|
|
9
|
+
*
|
|
10
|
+
* 同时支持 Kotlin DSL 和 Groovy DSL 的正则模式。
|
|
11
|
+
*/
|
|
12
|
+
// ── settings.gradle 解析模式 ─────────────────────────
|
|
13
|
+
const SETTINGS_ROOT_NAME_KT = /rootProject\.name\s*=\s*"([^"]+)"/;
|
|
14
|
+
const SETTINGS_ROOT_NAME_GR = /rootProject\.name\s*=\s*'([^']+)'/;
|
|
15
|
+
// Kotlin DSL: include(":core:network") 或 include(":app", ":core")
|
|
16
|
+
const INCLUDE_KT = /include\(\s*((?:"[^"]+"(?:\s*,\s*)?)+)\s*\)/g;
|
|
17
|
+
// Groovy DSL: include ':core:network' 或 include ':app', ':core'
|
|
18
|
+
const INCLUDE_GR = /include\s+((?:'[^']+'(?:\s*,\s*)?)+)/g;
|
|
19
|
+
// ── build.gradle 解析模式 ────────────────────────────
|
|
20
|
+
// Kotlin DSL: id("myapp.android.feature")
|
|
21
|
+
const PLUGIN_KT = /id\(\s*"([^"]+)"\s*\)/g;
|
|
22
|
+
// Groovy DSL: id 'myapp.android.feature'
|
|
23
|
+
const PLUGIN_GR = /id\s+'([^']+)'/g;
|
|
24
|
+
// Kotlin DSL: implementation(project(":core:network"))
|
|
25
|
+
const PROJECT_DEP_KT = /(implementation|api|compileOnly|testImplementation|runtimeOnly|kapt|ksp)\s*\(\s*project\(\s*"([^"]+)"\s*\)\s*\)/g;
|
|
26
|
+
// Groovy DSL: implementation project(':core:network')
|
|
27
|
+
const PROJECT_DEP_GR = /(implementation|api|compileOnly|testImplementation|runtimeOnly|kapt|ksp)\s+project\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
28
|
+
// kotlin("multiplatform") plugin detection
|
|
29
|
+
const KMP_PLUGIN_RE = /kotlin\(\s*"multiplatform"\s*\)/;
|
|
30
|
+
// ── 公开 API ────────────────────────────────────────
|
|
31
|
+
/**
|
|
32
|
+
* 解析 settings.gradle.kts / settings.gradle 内容
|
|
33
|
+
* 提取 rootProject 名和所有 include 模块
|
|
34
|
+
*
|
|
35
|
+
* 当传入 build 文件内容时(附带 module 参数),解析 plugins 和 dependencies 到该模块上
|
|
36
|
+
*/
|
|
37
|
+
export function parseGradleProject(content, existingModule) {
|
|
38
|
+
const result = {
|
|
39
|
+
rootProjectName: '',
|
|
40
|
+
includedModules: [],
|
|
41
|
+
};
|
|
42
|
+
// 如果传入了 existingModule,解析 build 文件内容
|
|
43
|
+
if (existingModule) {
|
|
44
|
+
const updatedMod = parseBuildFileForModule(content, existingModule);
|
|
45
|
+
result.includedModules = [updatedMod];
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
// 解析 rootProject.name
|
|
49
|
+
const rootNameKt = content.match(SETTINGS_ROOT_NAME_KT);
|
|
50
|
+
const rootNameGr = content.match(SETTINGS_ROOT_NAME_GR);
|
|
51
|
+
result.rootProjectName = rootNameKt?.[1] ?? rootNameGr?.[1] ?? '';
|
|
52
|
+
// 解析 include 声明
|
|
53
|
+
const modules = new Map();
|
|
54
|
+
// Kotlin DSL includes
|
|
55
|
+
const ktContent = content;
|
|
56
|
+
let m;
|
|
57
|
+
const ktIncludeRe = new RegExp(INCLUDE_KT.source, 'g');
|
|
58
|
+
while ((m = ktIncludeRe.exec(ktContent)) !== null) {
|
|
59
|
+
const innerStr = m[1];
|
|
60
|
+
const pathRe = /"([^"]+)"/g;
|
|
61
|
+
let pathMatch;
|
|
62
|
+
while ((pathMatch = pathRe.exec(innerStr)) !== null) {
|
|
63
|
+
const modPath = pathMatch[1];
|
|
64
|
+
if (!modules.has(modPath)) {
|
|
65
|
+
modules.set(modPath, {
|
|
66
|
+
path: modPath,
|
|
67
|
+
directory: modPath.replace(/^:/, '').replace(/:/g, '/'),
|
|
68
|
+
dependencies: [],
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Groovy DSL includes
|
|
74
|
+
const grIncludeRe = new RegExp(INCLUDE_GR.source, 'g');
|
|
75
|
+
while ((m = grIncludeRe.exec(content)) !== null) {
|
|
76
|
+
const innerStr = m[1];
|
|
77
|
+
const pathRe = /'([^']+)'/g;
|
|
78
|
+
let pathMatch;
|
|
79
|
+
while ((pathMatch = pathRe.exec(innerStr)) !== null) {
|
|
80
|
+
const modPath = pathMatch[1];
|
|
81
|
+
if (!modules.has(modPath)) {
|
|
82
|
+
modules.set(modPath, {
|
|
83
|
+
path: modPath,
|
|
84
|
+
directory: modPath.replace(/^:/, '').replace(/:/g, '/'),
|
|
85
|
+
dependencies: [],
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// 检测 version catalog
|
|
91
|
+
if (content.includes('libs.versions.toml') || content.includes('versionCatalogs')) {
|
|
92
|
+
result.versionCatalog = 'gradle/libs.versions.toml';
|
|
93
|
+
}
|
|
94
|
+
result.includedModules = [...modules.values()];
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* 检测 build 文件中是否使用了 Kotlin Multiplatform 插件
|
|
99
|
+
*/
|
|
100
|
+
export function isKmpBuildFile(content) {
|
|
101
|
+
return KMP_PLUGIN_RE.test(content);
|
|
102
|
+
}
|
|
103
|
+
// ── 内部函数 ────────────────────────────────────────
|
|
104
|
+
function parseBuildFileForModule(content, module) {
|
|
105
|
+
const result = { ...module, dependencies: [] };
|
|
106
|
+
// 提取 convention plugin
|
|
107
|
+
const pluginKtRe = new RegExp(PLUGIN_KT.source, 'g');
|
|
108
|
+
const pluginGrRe = new RegExp(PLUGIN_GR.source, 'g');
|
|
109
|
+
let m;
|
|
110
|
+
while ((m = pluginKtRe.exec(content)) !== null) {
|
|
111
|
+
const pluginId = m[1];
|
|
112
|
+
// Convention plugins 通常是项目自定义的(包含项目名前缀)
|
|
113
|
+
if (pluginId.includes('.') &&
|
|
114
|
+
!pluginId.startsWith('com.android') &&
|
|
115
|
+
!pluginId.startsWith('org.jetbrains')) {
|
|
116
|
+
result.conventionPlugin = pluginId;
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (!result.conventionPlugin) {
|
|
121
|
+
while ((m = pluginGrRe.exec(content)) !== null) {
|
|
122
|
+
const pluginId = m[1];
|
|
123
|
+
if (pluginId.includes('.') &&
|
|
124
|
+
!pluginId.startsWith('com.android') &&
|
|
125
|
+
!pluginId.startsWith('org.jetbrains')) {
|
|
126
|
+
result.conventionPlugin = pluginId;
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// 提取 project dependencies
|
|
132
|
+
const depKtRe = new RegExp(PROJECT_DEP_KT.source, 'g');
|
|
133
|
+
const depGrRe = new RegExp(PROJECT_DEP_GR.source, 'g');
|
|
134
|
+
while ((m = depKtRe.exec(content)) !== null) {
|
|
135
|
+
result.dependencies.push({
|
|
136
|
+
configuration: m[1],
|
|
137
|
+
target: m[2],
|
|
138
|
+
isProject: true,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
while ((m = depGrRe.exec(content)) !== null) {
|
|
142
|
+
result.dependencies.push({
|
|
143
|
+
configuration: m[1],
|
|
144
|
+
target: m[2],
|
|
145
|
+
isProject: true,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return result;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* 从 convention plugin id 推断模块角色
|
|
152
|
+
* 例: "myapp.android.feature" → "feature"
|
|
153
|
+
*/
|
|
154
|
+
export function inferConventionRole(pluginId) {
|
|
155
|
+
const parts = pluginId.split('.');
|
|
156
|
+
const last = parts[parts.length - 1];
|
|
157
|
+
const ROLE_KEYWORDS = {
|
|
158
|
+
feature: 'feature',
|
|
159
|
+
library: 'library',
|
|
160
|
+
app: 'application',
|
|
161
|
+
application: 'application',
|
|
162
|
+
core: 'core',
|
|
163
|
+
data: 'data',
|
|
164
|
+
domain: 'domain',
|
|
165
|
+
ui: 'ui',
|
|
166
|
+
test: 'test',
|
|
167
|
+
compose: 'compose',
|
|
168
|
+
hilt: 'di',
|
|
169
|
+
};
|
|
170
|
+
return ROLE_KEYWORDS[last] ?? undefined;
|
|
171
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module JsonConfigParser
|
|
3
|
+
* @description JSON 配置文件解析器 — 支持 Nx project.json、Flutter 插件依赖、React Native 检测
|
|
4
|
+
*
|
|
5
|
+
* 每个解析函数接受文件内容字符串,返回类型化结果。
|
|
6
|
+
*/
|
|
7
|
+
export interface ParsedNxWorkspace {
|
|
8
|
+
projects: NxProject[];
|
|
9
|
+
}
|
|
10
|
+
export interface NxProject {
|
|
11
|
+
name: string;
|
|
12
|
+
root: string;
|
|
13
|
+
projectType: string;
|
|
14
|
+
tags: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface ParsedFlutterPluginsDeps {
|
|
17
|
+
plugins: FlutterPlugin[];
|
|
18
|
+
flutterSdkVersion?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface FlutterPlugin {
|
|
21
|
+
name: string;
|
|
22
|
+
path: string;
|
|
23
|
+
platform: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ParsedReactNativeProject {
|
|
26
|
+
isReactNative: boolean;
|
|
27
|
+
name: string;
|
|
28
|
+
rnVersion?: string;
|
|
29
|
+
hasFabric?: boolean;
|
|
30
|
+
hasTurboModules?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 解析 Nx project.json 内容
|
|
34
|
+
* 每个 project.json 描述一个项目
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseNxWorkspace(content: string): ParsedNxWorkspace;
|
|
37
|
+
/**
|
|
38
|
+
* 解析 .flutter-plugins-dependencies 文件内容
|
|
39
|
+
* 该文件由 Flutter 工具链自动生成
|
|
40
|
+
*/
|
|
41
|
+
export declare function parseFlutterPluginsDeps(content: string): ParsedFlutterPluginsDeps;
|
|
42
|
+
/**
|
|
43
|
+
* 解析 package.json 内容,判断是否是 React Native 项目
|
|
44
|
+
*/
|
|
45
|
+
export declare function parseReactNativeProject(content: string): ParsedReactNativeProject;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module JsonConfigParser
|
|
3
|
+
* @description JSON 配置文件解析器 — 支持 Nx project.json、Flutter 插件依赖、React Native 检测
|
|
4
|
+
*
|
|
5
|
+
* 每个解析函数接受文件内容字符串,返回类型化结果。
|
|
6
|
+
*/
|
|
7
|
+
// ── Nx 解析 ─────────────────────────────────────────
|
|
8
|
+
/**
|
|
9
|
+
* 解析 Nx project.json 内容
|
|
10
|
+
* 每个 project.json 描述一个项目
|
|
11
|
+
*/
|
|
12
|
+
export function parseNxWorkspace(content) {
|
|
13
|
+
const result = { projects: [] };
|
|
14
|
+
try {
|
|
15
|
+
const json = JSON.parse(content);
|
|
16
|
+
const name = json.name ?? '';
|
|
17
|
+
const root = json.root ?? json.sourceRoot ?? '.';
|
|
18
|
+
const projectType = json.projectType ?? 'library';
|
|
19
|
+
const tags = Array.isArray(json.tags) ? json.tags : [];
|
|
20
|
+
if (name) {
|
|
21
|
+
result.projects.push({ name, root, projectType, tags });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// JSON 解析失败时返回空结果
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
// ── Flutter 解析 ────────────────────────────────────
|
|
30
|
+
/**
|
|
31
|
+
* 解析 .flutter-plugins-dependencies 文件内容
|
|
32
|
+
* 该文件由 Flutter 工具链自动生成
|
|
33
|
+
*/
|
|
34
|
+
export function parseFlutterPluginsDeps(content) {
|
|
35
|
+
const result = { plugins: [] };
|
|
36
|
+
try {
|
|
37
|
+
const json = JSON.parse(content);
|
|
38
|
+
// dependencyGraph 数组包含 Flutter embedding 信息
|
|
39
|
+
const depGraph = json.dependencyGraph;
|
|
40
|
+
if (Array.isArray(depGraph)) {
|
|
41
|
+
for (const entry of depGraph) {
|
|
42
|
+
if (typeof entry === 'object' && entry !== null) {
|
|
43
|
+
const rec = entry;
|
|
44
|
+
const name = rec.name ?? '';
|
|
45
|
+
if (name && name !== 'flutter') {
|
|
46
|
+
result.plugins.push({
|
|
47
|
+
name,
|
|
48
|
+
path: rec.path ?? '',
|
|
49
|
+
platform: 'flutter',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// 也解析 plugins.ios / plugins.android 中的平台插件
|
|
56
|
+
const plugins = json.plugins;
|
|
57
|
+
if (typeof plugins === 'object' && plugins !== null) {
|
|
58
|
+
const platformPlugins = plugins;
|
|
59
|
+
for (const [platform, list] of Object.entries(platformPlugins)) {
|
|
60
|
+
if (Array.isArray(list)) {
|
|
61
|
+
for (const p of list) {
|
|
62
|
+
if (typeof p === 'object' && p !== null) {
|
|
63
|
+
const rec = p;
|
|
64
|
+
const name = rec.name ?? '';
|
|
65
|
+
// 避免重复
|
|
66
|
+
if (name &&
|
|
67
|
+
!result.plugins.some((existing) => existing.name === name && existing.platform === platform)) {
|
|
68
|
+
result.plugins.push({
|
|
69
|
+
name,
|
|
70
|
+
path: rec.path ?? '',
|
|
71
|
+
platform,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Flutter SDK 版本
|
|
80
|
+
if (typeof json.flutterVersion === 'string') {
|
|
81
|
+
result.flutterSdkVersion = json.flutterVersion;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// JSON 解析失败时返回空结果
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
// ── React Native 解析 ──────────────────────────────
|
|
90
|
+
/**
|
|
91
|
+
* 解析 package.json 内容,判断是否是 React Native 项目
|
|
92
|
+
*/
|
|
93
|
+
export function parseReactNativeProject(content) {
|
|
94
|
+
const result = {
|
|
95
|
+
isReactNative: false,
|
|
96
|
+
name: '',
|
|
97
|
+
};
|
|
98
|
+
try {
|
|
99
|
+
const json = JSON.parse(content);
|
|
100
|
+
result.name = json.name ?? '';
|
|
101
|
+
const deps = (json.dependencies ?? {});
|
|
102
|
+
const devDeps = (json.devDependencies ?? {});
|
|
103
|
+
if (deps['react-native'] || devDeps['react-native']) {
|
|
104
|
+
result.isReactNative = true;
|
|
105
|
+
result.rnVersion = deps['react-native'] ?? devDeps['react-native'];
|
|
106
|
+
}
|
|
107
|
+
// Fabric (new architecture) 检测
|
|
108
|
+
if (result.isReactNative) {
|
|
109
|
+
const scripts = (json.scripts ?? {});
|
|
110
|
+
result.hasFabric =
|
|
111
|
+
deps['react-native-codegen'] !== undefined ||
|
|
112
|
+
Object.values(scripts).some((s) => s.includes('codegen'));
|
|
113
|
+
// TurboModules 检测
|
|
114
|
+
result.hasTurboModules =
|
|
115
|
+
typeof json.codegenConfig === 'object' || deps['react-native-turbo-modules'] !== undefined;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// JSON 解析失败时返回空结果
|
|
120
|
+
}
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module RubyDslParser
|
|
3
|
+
* @description Ruby DSL 轻量解析器 — 从 Boxfile / podspec 类文件中提取项目结构信息
|
|
4
|
+
*
|
|
5
|
+
* 不需要完整的 Ruby 解析器,使用正则 + 上下文状态机提取:
|
|
6
|
+
* - 层级 (layer) 声明与层间访问规则
|
|
7
|
+
* - 模块 (box) 声明(本地/远程)
|
|
8
|
+
* - 宿主应用信息
|
|
9
|
+
* - 模块级 spec 依赖/源文件路径
|
|
10
|
+
*
|
|
11
|
+
* 支持 EasyBox (Boxfile + *.boxspec) 和结构类似的自研工具。
|
|
12
|
+
*/
|
|
13
|
+
export interface ParsedModule {
|
|
14
|
+
name: string;
|
|
15
|
+
version: string;
|
|
16
|
+
isLocal: boolean;
|
|
17
|
+
localPath?: string;
|
|
18
|
+
group?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ParsedLayer {
|
|
21
|
+
name: string;
|
|
22
|
+
order: number;
|
|
23
|
+
accessibleLayers: string[];
|
|
24
|
+
modules: ParsedModule[];
|
|
25
|
+
}
|
|
26
|
+
export interface ParsedProjectConfig {
|
|
27
|
+
hostApp?: {
|
|
28
|
+
name: string;
|
|
29
|
+
version: string;
|
|
30
|
+
};
|
|
31
|
+
layers: ParsedLayer[];
|
|
32
|
+
globalDependencies: ParsedModule[];
|
|
33
|
+
}
|
|
34
|
+
export interface ParsedModuleSpec {
|
|
35
|
+
name: string;
|
|
36
|
+
version: string;
|
|
37
|
+
sources: string;
|
|
38
|
+
dependencies: string[];
|
|
39
|
+
publicHeaders: string[];
|
|
40
|
+
deploymentTarget?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 解析 Boxfile 内容,提取层级、模块、宿主应用信息
|
|
44
|
+
*/
|
|
45
|
+
export declare function parseBoxfile(content: string): ParsedProjectConfig;
|
|
46
|
+
/**
|
|
47
|
+
* 解析 boxspec/podspec 文件内容,提取模块元数据
|
|
48
|
+
*/
|
|
49
|
+
export declare function parseModuleSpec(content: string): ParsedModuleSpec;
|
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module RubyDslParser
|
|
3
|
+
* @description Ruby DSL 轻量解析器 — 从 Boxfile / podspec 类文件中提取项目结构信息
|
|
4
|
+
*
|
|
5
|
+
* 不需要完整的 Ruby 解析器,使用正则 + 上下文状态机提取:
|
|
6
|
+
* - 层级 (layer) 声明与层间访问规则
|
|
7
|
+
* - 模块 (box) 声明(本地/远程)
|
|
8
|
+
* - 宿主应用信息
|
|
9
|
+
* - 模块级 spec 依赖/源文件路径
|
|
10
|
+
*
|
|
11
|
+
* 支持 EasyBox (Boxfile + *.boxspec) 和结构类似的自研工具。
|
|
12
|
+
*/
|
|
13
|
+
// ── Boxfile 解析 ────────────────────────────────────
|
|
14
|
+
/**
|
|
15
|
+
* 解析 Boxfile 内容,提取层级、模块、宿主应用信息
|
|
16
|
+
*/
|
|
17
|
+
export function parseBoxfile(content) {
|
|
18
|
+
const result = {
|
|
19
|
+
layers: [],
|
|
20
|
+
globalDependencies: [],
|
|
21
|
+
};
|
|
22
|
+
// 提取 host_app
|
|
23
|
+
const hostAppMatch = content.match(/host_app\s+['"]([^'"]+)['"]\s*(?:,\s*['"]([^'"]+)['"])?/);
|
|
24
|
+
if (hostAppMatch) {
|
|
25
|
+
result.hostApp = {
|
|
26
|
+
name: hostAppMatch[1],
|
|
27
|
+
version: hostAppMatch[2] || '0.0.0',
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// 按 layer block 分割解析
|
|
31
|
+
const layerBlocks = extractLayerBlocks(content);
|
|
32
|
+
let layerOrder = 0;
|
|
33
|
+
for (const block of layerBlocks) {
|
|
34
|
+
const layer = {
|
|
35
|
+
name: block.name,
|
|
36
|
+
order: layerOrder++,
|
|
37
|
+
accessibleLayers: extractAccessLayers(block.body),
|
|
38
|
+
modules: extractModules(block.body),
|
|
39
|
+
};
|
|
40
|
+
result.layers.push(layer);
|
|
41
|
+
}
|
|
42
|
+
// 提取 layer 外层的全局模块声明
|
|
43
|
+
const outsideLayerContent = removeLayerBlocks(content);
|
|
44
|
+
result.globalDependencies = extractModules(outsideLayerContent);
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
// ── *.boxspec / *.podspec 解析 ────────────────────────
|
|
48
|
+
/**
|
|
49
|
+
* 解析 boxspec/podspec 文件内容,提取模块元数据
|
|
50
|
+
*/
|
|
51
|
+
export function parseModuleSpec(content) {
|
|
52
|
+
return {
|
|
53
|
+
name: extractSpecField(content, 'name') || 'unknown',
|
|
54
|
+
version: extractSpecField(content, 'version') || '0.0.0',
|
|
55
|
+
sources: extractSpecField(content, 'source_files') ||
|
|
56
|
+
extractSpecField(content, 'sources') ||
|
|
57
|
+
extractSpecField(content, 'source') ||
|
|
58
|
+
'',
|
|
59
|
+
dependencies: extractSpecDependencies(content),
|
|
60
|
+
publicHeaders: extractSpecArrayField(content, 'public_headers') ||
|
|
61
|
+
extractSpecArrayField(content, 'public_header_files') ||
|
|
62
|
+
[],
|
|
63
|
+
deploymentTarget: extractSpecDeploymentTarget(content),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* 提取所有 layer 'Name' do ... end 块
|
|
68
|
+
* 使用 do/end 嵌套计数处理嵌套 block
|
|
69
|
+
*/
|
|
70
|
+
function extractLayerBlocks(content) {
|
|
71
|
+
const blocks = [];
|
|
72
|
+
const layerRe = /layer\s+['"](\w+)['"]\s+do\b/g;
|
|
73
|
+
let match;
|
|
74
|
+
while ((match = layerRe.exec(content)) !== null) {
|
|
75
|
+
const name = match[1];
|
|
76
|
+
const startIndex = match.index;
|
|
77
|
+
const bodyStart = match.index + match[0].length;
|
|
78
|
+
const endIndex = findMatchingEnd(content, bodyStart);
|
|
79
|
+
if (endIndex === -1) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
blocks.push({
|
|
83
|
+
name,
|
|
84
|
+
body: content.substring(bodyStart, endIndex),
|
|
85
|
+
startIndex,
|
|
86
|
+
endIndex: endIndex + 3, // 'end' is 3 chars
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return blocks;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 从 do 之后的位置开始,找到匹配的 end
|
|
93
|
+
* 处理嵌套的 do...end 块(如 group do ... end)
|
|
94
|
+
*/
|
|
95
|
+
function findMatchingEnd(content, startPos) {
|
|
96
|
+
let depth = 1;
|
|
97
|
+
// 逐行扫描以正确识别 do/end 关键字(避免匹配字符串内的)
|
|
98
|
+
const lines = content.substring(startPos).split('\n');
|
|
99
|
+
let pos = startPos;
|
|
100
|
+
for (const line of lines) {
|
|
101
|
+
const trimmed = line.trim();
|
|
102
|
+
// 跳过注释行
|
|
103
|
+
if (trimmed.startsWith('#')) {
|
|
104
|
+
pos += line.length + 1;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
// 计算该行的 do 和 end
|
|
108
|
+
// 匹配行尾的 do(不匹配字符串内的)
|
|
109
|
+
if (/\bdo\b\s*(?:#.*)?$/.test(trimmed)) {
|
|
110
|
+
depth++;
|
|
111
|
+
}
|
|
112
|
+
// 匹配行首的 end(独立的 end 关键字)
|
|
113
|
+
if (/^\s*end\b/.test(line)) {
|
|
114
|
+
depth--;
|
|
115
|
+
if (depth === 0) {
|
|
116
|
+
return pos;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
pos += line.length + 1;
|
|
120
|
+
}
|
|
121
|
+
return -1;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* 移除所有 layer 块,返回剩余内容(用于提取全局模块)
|
|
125
|
+
*/
|
|
126
|
+
function removeLayerBlocks(content) {
|
|
127
|
+
const blocks = extractLayerBlocks(content);
|
|
128
|
+
if (blocks.length === 0) {
|
|
129
|
+
return content;
|
|
130
|
+
}
|
|
131
|
+
let result = '';
|
|
132
|
+
let lastEnd = 0;
|
|
133
|
+
for (const block of blocks) {
|
|
134
|
+
result += content.substring(lastEnd, block.startIndex);
|
|
135
|
+
lastEnd = block.endIndex;
|
|
136
|
+
}
|
|
137
|
+
result += content.substring(lastEnd);
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
// ── Box/模块提取 ────────────────────────────────────
|
|
141
|
+
/**
|
|
142
|
+
* 从内容中提取所有 box 声明
|
|
143
|
+
*
|
|
144
|
+
* 支持格式:
|
|
145
|
+
* box 'Name', 'Version'
|
|
146
|
+
* box 'Name', :path => 'LocalModule/Name'
|
|
147
|
+
* box 'Name', path: 'LocalModule/Name'
|
|
148
|
+
* box 'Name', '~> 1.0', :path => '...'
|
|
149
|
+
*/
|
|
150
|
+
function extractModules(content) {
|
|
151
|
+
const modules = [];
|
|
152
|
+
const seen = new Set();
|
|
153
|
+
// 当前 group 上下文跟踪
|
|
154
|
+
let currentGroup;
|
|
155
|
+
const lines = content.split('\n');
|
|
156
|
+
for (const line of lines) {
|
|
157
|
+
const trimmed = line.trim();
|
|
158
|
+
// 跳过注释
|
|
159
|
+
if (trimmed.startsWith('#')) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
// 检查 group 开始
|
|
163
|
+
const groupMatch = trimmed.match(/group\s+['"]([^'"]+)['"]\s+do/);
|
|
164
|
+
if (groupMatch) {
|
|
165
|
+
currentGroup = groupMatch[1];
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
// 检查 group/layer 结束
|
|
169
|
+
if (/^\s*end\b/.test(line) && currentGroup) {
|
|
170
|
+
currentGroup = undefined;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
// 解析 box 声明
|
|
174
|
+
const boxMatch = trimmed.match(/^box\s+['"]([^'"]+)['"]/);
|
|
175
|
+
if (!boxMatch) {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const name = boxMatch[1];
|
|
179
|
+
if (seen.has(name)) {
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
seen.add(name);
|
|
183
|
+
const rest = trimmed.substring(boxMatch[0].length);
|
|
184
|
+
// 检查是否有 :path(本地模块)
|
|
185
|
+
const pathMatch = rest.match(/:path\s*=>\s*['"]([^'"]+)['"]|path:\s*['"]([^'"]+)['"]/);
|
|
186
|
+
const isLocal = pathMatch !== null;
|
|
187
|
+
const localPath = pathMatch ? pathMatch[1] || pathMatch[2] : undefined;
|
|
188
|
+
// 提取版本号
|
|
189
|
+
let version = '';
|
|
190
|
+
const versionMatch = rest.match(/,\s*['"]([^'"]+)['"]/);
|
|
191
|
+
if (versionMatch && !versionMatch[1].includes('/')) {
|
|
192
|
+
version = versionMatch[1];
|
|
193
|
+
}
|
|
194
|
+
modules.push({
|
|
195
|
+
name,
|
|
196
|
+
version,
|
|
197
|
+
isLocal,
|
|
198
|
+
localPath,
|
|
199
|
+
group: currentGroup,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
return modules;
|
|
203
|
+
}
|
|
204
|
+
// ── Access 规则提取 ─────────────────────────────────
|
|
205
|
+
/**
|
|
206
|
+
* 提取 access 声明中的层名列表
|
|
207
|
+
*
|
|
208
|
+
* 支持格式:
|
|
209
|
+
* access 'Layer1', 'Layer2', 'Layer3'
|
|
210
|
+
* access "Layer1", "Layer2"
|
|
211
|
+
*/
|
|
212
|
+
function extractAccessLayers(content) {
|
|
213
|
+
const layers = [];
|
|
214
|
+
const accessRe = /access\s+(.+)/g;
|
|
215
|
+
let match;
|
|
216
|
+
while ((match = accessRe.exec(content)) !== null) {
|
|
217
|
+
const rest = match[1];
|
|
218
|
+
const nameRe = /['"]([^'"]+)['"]/g;
|
|
219
|
+
let nameMatch;
|
|
220
|
+
while ((nameMatch = nameRe.exec(rest)) !== null) {
|
|
221
|
+
if (!layers.includes(nameMatch[1])) {
|
|
222
|
+
layers.push(nameMatch[1]);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return layers;
|
|
227
|
+
}
|
|
228
|
+
// ── Spec 字段提取 ───────────────────────────────────
|
|
229
|
+
/**
|
|
230
|
+
* 从 podspec/boxspec 中提取单值字段
|
|
231
|
+
* 支持: s.name = 'Value' 和 spec.name = 'Value'
|
|
232
|
+
*/
|
|
233
|
+
function extractSpecField(content, field) {
|
|
234
|
+
const re = new RegExp(`\\b\\w+\\.${field}\\s*=\\s*['"]([^'"]+)['"]`, 'i');
|
|
235
|
+
const match = content.match(re);
|
|
236
|
+
return match ? match[1] : undefined;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* 从 podspec/boxspec 中提取 dependency 声明列表
|
|
240
|
+
*
|
|
241
|
+
* 支持:
|
|
242
|
+
* s.dependency 'ModuleName'
|
|
243
|
+
* s.dependency 'ModuleName', '~> 1.0'
|
|
244
|
+
* s.dependency "ModuleName"
|
|
245
|
+
*/
|
|
246
|
+
function extractSpecDependencies(content) {
|
|
247
|
+
const deps = [];
|
|
248
|
+
const re = /\b\w+\.dependency\s+['"]([^'"]+)['"]/g;
|
|
249
|
+
let match;
|
|
250
|
+
while ((match = re.exec(content)) !== null) {
|
|
251
|
+
if (!deps.includes(match[1])) {
|
|
252
|
+
deps.push(match[1]);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return deps;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* 从 podspec/boxspec 中提取数组字段
|
|
259
|
+
* 支持: s.public_headers = ['path1', 'path2']
|
|
260
|
+
*/
|
|
261
|
+
function extractSpecArrayField(content, field) {
|
|
262
|
+
const re = new RegExp(`\\b\\w+\\.${field}\\s*=\\s*\\[([^\\]]+)\\]`, 'i');
|
|
263
|
+
const match = content.match(re);
|
|
264
|
+
if (!match) {
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
const items = [];
|
|
268
|
+
const itemRe = /['"]([^'"]+)['"]/g;
|
|
269
|
+
let m;
|
|
270
|
+
while ((m = itemRe.exec(match[1])) !== null) {
|
|
271
|
+
items.push(m[1]);
|
|
272
|
+
}
|
|
273
|
+
return items.length > 0 ? items : undefined;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* 提取部署目标版本
|
|
277
|
+
* 支持: s.ios.deployment_target = '13.0'
|
|
278
|
+
*/
|
|
279
|
+
function extractSpecDeploymentTarget(content) {
|
|
280
|
+
const match = content.match(/\b\w+\.ios\.deployment_target\s*=\s*['"]([^'"]+)['"]/);
|
|
281
|
+
return match ? match[1] : undefined;
|
|
282
|
+
}
|