autosnippet 3.0.0 → 3.0.2
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 +230 -324
- package/bin/api-server.js +1 -1
- package/bin/cli.js +204 -244
- package/bin/mcp-server.js +5 -3
- package/config/knowledge-base.config.js +132 -132
- package/dashboard/dist/assets/{icons-CEfgGaZi.js → icons-Cdq22n2i.js} +95 -100
- package/dashboard/dist/assets/index-ClkyPkDX.js +133 -0
- package/dashboard/dist/assets/index-t4QrJwv1.css +1 -0
- package/dashboard/dist/index.html +3 -3
- package/lib/bootstrap.js +8 -8
- package/lib/cli/AiScanService.js +86 -40
- package/lib/cli/KnowledgeSyncService.js +113 -74
- package/lib/cli/SetupService.js +439 -277
- package/lib/cli/UpgradeService.js +63 -100
- package/lib/core/AstAnalyzer.js +276 -597
- package/lib/core/ast/ProjectGraph.js +101 -40
- package/lib/core/ast/ensure-grammars.js +232 -0
- package/lib/core/ast/index.js +115 -0
- package/lib/core/ast/lang-dart.js +661 -0
- package/lib/core/ast/lang-go.js +530 -0
- package/lib/core/ast/lang-java.js +435 -0
- package/lib/core/ast/lang-javascript.js +272 -0
- package/lib/core/ast/lang-kotlin.js +423 -0
- package/lib/core/ast/lang-objc.js +388 -0
- package/lib/core/ast/lang-python.js +371 -0
- package/lib/core/ast/lang-swift.js +337 -0
- package/lib/core/ast/lang-typescript.js +503 -0
- package/lib/core/capability/CapabilityProbe.js +18 -9
- package/lib/core/constitution/Constitution.js +2 -3
- package/lib/core/constitution/ConstitutionValidator.js +65 -24
- package/lib/core/discovery/DartDiscoverer.js +534 -0
- package/lib/core/discovery/DiscovererRegistry.js +83 -0
- package/lib/core/discovery/GenericDiscoverer.js +225 -0
- package/lib/core/discovery/GoDiscoverer.js +541 -0
- package/lib/core/discovery/JvmDiscoverer.js +506 -0
- package/lib/core/discovery/NodeDiscoverer.js +466 -0
- package/lib/core/discovery/ProjectDiscoverer.js +93 -0
- package/lib/core/discovery/PythonDiscoverer.js +338 -0
- package/lib/core/discovery/SpmDiscoverer.js +5 -0
- package/lib/core/discovery/index.js +53 -0
- package/lib/core/enhancement/EnhancementPack.js +71 -0
- package/lib/core/enhancement/EnhancementRegistry.js +47 -0
- package/lib/core/enhancement/android-enhancement.js +102 -0
- package/lib/core/enhancement/django-enhancement.js +70 -0
- package/lib/core/enhancement/fastapi-enhancement.js +63 -0
- package/lib/core/enhancement/go-grpc-enhancement.js +152 -0
- package/lib/core/enhancement/go-web-enhancement.js +201 -0
- package/lib/core/enhancement/index.js +65 -0
- package/lib/core/enhancement/node-server-enhancement.js +88 -0
- package/lib/core/enhancement/react-enhancement.js +86 -0
- package/lib/core/enhancement/spring-enhancement.js +112 -0
- package/lib/core/enhancement/vue-enhancement.js +96 -0
- package/lib/core/gateway/Gateway.js +8 -9
- package/lib/core/gateway/GatewayActionRegistry.js +1 -1
- package/lib/core/permission/PermissionManager.js +12 -8
- package/lib/domain/index.js +13 -9
- package/lib/domain/knowledge/KnowledgeEntry.js +111 -101
- package/lib/domain/knowledge/KnowledgeRepository.js +0 -1
- package/lib/domain/knowledge/Lifecycle.js +22 -22
- package/lib/domain/knowledge/index.js +9 -12
- package/lib/domain/knowledge/values/Constraints.js +31 -21
- package/lib/domain/knowledge/values/Content.js +21 -13
- package/lib/domain/knowledge/values/Quality.js +31 -18
- package/lib/domain/knowledge/values/Reasoning.js +20 -12
- package/lib/domain/knowledge/values/Relations.js +37 -25
- package/lib/domain/knowledge/values/Stats.js +18 -12
- package/lib/domain/knowledge/values/index.js +4 -3
- package/lib/domain/snippet/Snippet.js +35 -10
- package/lib/external/ai/AiFactory.js +48 -16
- package/lib/external/ai/AiProvider.js +184 -90
- package/lib/external/ai/providers/ClaudeProvider.js +25 -12
- package/lib/external/ai/providers/GoogleGeminiProvider.js +59 -30
- package/lib/external/ai/providers/MockProvider.js +9 -3
- package/lib/external/ai/providers/OpenAiProvider.js +51 -29
- package/lib/external/mcp/McpServer.js +66 -36
- package/lib/external/mcp/errorHandler.js +23 -11
- package/lib/external/mcp/handlers/LanguageExtensions.js +138 -53
- package/lib/external/mcp/handlers/TargetClassifier.js +52 -16
- package/lib/external/mcp/handlers/bootstrap/pipeline/BootstrapSnapshot.js +81 -20
- package/lib/external/mcp/handlers/bootstrap/pipeline/EpisodicMemory.js +71 -42
- package/lib/external/mcp/handlers/bootstrap/pipeline/IncrementalBootstrap.js +9 -17
- package/lib/external/mcp/handlers/bootstrap/pipeline/ToolResultCache.js +14 -9
- package/lib/external/mcp/handlers/bootstrap/pipeline/dimension-context.js +15 -7
- package/lib/external/mcp/handlers/bootstrap/pipeline/orchestrator.js +352 -153
- package/lib/external/mcp/handlers/bootstrap/pipeline/tier-scheduler.js +52 -12
- package/lib/external/mcp/handlers/bootstrap/skills.js +143 -39
- package/lib/external/mcp/handlers/bootstrap.js +691 -168
- package/lib/external/mcp/handlers/browse.js +66 -22
- package/lib/external/mcp/handlers/candidate.js +118 -35
- package/lib/external/mcp/handlers/consolidated.js +49 -17
- package/lib/external/mcp/handlers/guard.js +104 -39
- package/lib/external/mcp/handlers/knowledge.js +60 -36
- package/lib/external/mcp/handlers/search.js +43 -14
- package/lib/external/mcp/handlers/skill.js +120 -45
- package/lib/external/mcp/handlers/structure.js +240 -86
- package/lib/external/mcp/handlers/system.js +42 -12
- package/lib/external/mcp/handlers/wiki.js +58 -33
- package/lib/external/mcp/tools.js +306 -123
- package/lib/http/HttpServer.js +72 -47
- package/lib/http/middleware/RateLimiter.js +5 -3
- package/lib/http/middleware/errorHandler.js +6 -1
- package/lib/http/middleware/requestLogger.js +14 -3
- package/lib/http/middleware/roleResolver.js +30 -23
- package/lib/http/routes/ai.js +387 -265
- package/lib/http/routes/auth.js +81 -61
- package/lib/http/routes/candidates.js +430 -320
- package/lib/http/routes/commands.js +289 -189
- package/lib/http/routes/extract.js +158 -125
- package/lib/http/routes/guardRules.js +309 -217
- package/lib/http/routes/knowledge.js +213 -154
- package/lib/http/routes/modules.js +578 -0
- package/lib/http/routes/monitoring.js +6 -6
- package/lib/http/routes/recipes.js +104 -93
- package/lib/http/routes/search.js +361 -305
- package/lib/http/routes/skills.js +145 -98
- package/lib/http/routes/snippets.js +42 -30
- package/lib/http/routes/spm.js +3 -405
- package/lib/http/routes/violations.js +113 -93
- package/lib/http/routes/wiki.js +211 -170
- package/lib/http/utils/routeHelpers.js +3 -1
- package/lib/http/utils/sse-sessions.js +16 -6
- package/lib/http/utils/sse.js +15 -5
- package/lib/infrastructure/audit/AuditLogger.js +5 -2
- package/lib/infrastructure/audit/AuditStore.js +10 -7
- package/lib/infrastructure/cache/CacheService.js +3 -1
- package/lib/infrastructure/cache/GraphCache.js +8 -4
- package/lib/infrastructure/cache/UnifiedCacheAdapter.js +1 -1
- package/lib/infrastructure/config/ConfigLoader.js +9 -5
- package/lib/infrastructure/config/Defaults.js +30 -10
- package/lib/infrastructure/config/Paths.js +28 -8
- package/lib/infrastructure/config/TriggerSymbol.js +22 -10
- package/lib/infrastructure/database/DatabaseConnection.js +15 -10
- package/lib/infrastructure/database/migrations/001_initial_schema.js +0 -1
- package/lib/infrastructure/external/ClipboardManager.js +6 -2
- package/lib/infrastructure/external/NativeUi.js +50 -43
- package/lib/infrastructure/external/OpenBrowser.js +14 -17
- package/lib/infrastructure/external/XcodeAutomation.js +14 -258
- package/lib/infrastructure/logging/Logger.js +46 -30
- package/lib/infrastructure/monitoring/ErrorTracker.js +7 -5
- package/lib/infrastructure/monitoring/PerformanceMonitor.js +12 -4
- package/lib/infrastructure/paths/HeaderResolver.js +25 -9
- package/lib/infrastructure/paths/PathFinder.js +34 -12
- package/lib/infrastructure/plugin/PluginManager.js +26 -8
- package/lib/infrastructure/realtime/RealtimeService.js +2 -2
- package/lib/infrastructure/vector/Chunker.js +22 -7
- package/lib/infrastructure/vector/IndexingPipeline.js +46 -22
- package/lib/infrastructure/vector/JsonVectorAdapter.js +90 -53
- package/lib/infrastructure/vector/VectorStore.js +28 -10
- package/lib/injection/ServiceContainer.js +247 -93
- package/lib/platform/ios/index.js +63 -0
- package/lib/platform/ios/routes/spm.js +437 -0
- package/lib/platform/ios/snippet/PlaceholderConverter.js +55 -0
- package/lib/platform/ios/snippet/XcodeCodec.js +112 -0
- package/lib/{service → platform/ios}/spm/DependencyGraph.js +41 -17
- package/lib/{service → platform/ios}/spm/PackageSwiftParser.js +41 -14
- package/lib/{service → platform/ios}/spm/PolicyEngine.js +9 -4
- package/lib/platform/ios/spm/SpmDiscoverer.js +122 -0
- package/lib/{service → platform/ios}/spm/SpmService.js +385 -127
- package/lib/{service/automation → platform/ios/xcode}/SaveEventFilter.js +8 -7
- package/lib/platform/ios/xcode/XcodeAutomation.js +350 -0
- package/lib/{service/automation → platform/ios/xcode}/XcodeIntegration.js +325 -145
- package/lib/repository/base/BaseRepository.js +7 -9
- package/lib/repository/knowledge/KnowledgeRepository.impl.js +98 -75
- package/lib/repository/token/TokenUsageStore.js +4 -2
- package/lib/service/automation/ActionPipeline.js +1 -1
- package/lib/service/automation/AutomationOrchestrator.js +8 -4
- package/lib/service/automation/ContextCollector.js +7 -5
- package/lib/service/automation/DirectiveDetector.js +23 -16
- package/lib/service/automation/FileWatcher.js +112 -56
- package/lib/service/automation/TriggerResolver.js +6 -4
- package/lib/service/automation/handlers/AlinkHandler.js +24 -12
- package/lib/service/automation/handlers/CreateHandler.js +19 -20
- package/lib/service/automation/handlers/DraftHandler.js +14 -8
- package/lib/service/automation/handlers/GuardHandler.js +93 -63
- package/lib/service/automation/handlers/HeaderHandler.js +1 -6
- package/lib/service/automation/handlers/SearchHandler.js +155 -88
- package/lib/service/bootstrap/BootstrapTaskManager.js +77 -35
- package/lib/service/candidate/SimilarityService.js +25 -9
- package/lib/service/chat/AnalystAgent.js +50 -24
- package/lib/service/chat/CandidateGuardrail.js +143 -17
- package/lib/service/chat/ChatAgent.js +759 -243
- package/lib/service/chat/ContextWindow.js +116 -71
- package/lib/service/chat/ConversationStore.js +77 -36
- package/lib/service/chat/EpisodicConsolidator.js +47 -23
- package/lib/service/chat/HandoffProtocol.js +98 -22
- package/lib/service/chat/Memory.js +34 -14
- package/lib/service/chat/ProducerAgent.js +40 -20
- package/lib/service/chat/ProjectSemanticMemory.js +109 -78
- package/lib/service/chat/ReasoningLayer.js +148 -70
- package/lib/service/chat/ReasoningTrace.js +44 -32
- package/lib/service/chat/TaskPipeline.js +39 -19
- package/lib/service/chat/ToolRegistry.js +48 -29
- package/lib/service/chat/WorkingMemory.js +44 -18
- package/lib/service/chat/tools.js +1096 -494
- package/lib/service/context/RecipeExtractor.js +132 -51
- package/lib/service/cursor/CursorDeliveryPipeline.js +82 -37
- package/lib/service/cursor/KnowledgeCompressor.js +25 -22
- package/lib/service/cursor/RulesGenerator.js +13 -7
- package/lib/service/cursor/SkillsSyncer.js +77 -27
- package/lib/service/cursor/TokenBudget.js +2 -2
- package/lib/service/cursor/TopicClassifier.js +54 -20
- package/lib/service/guard/ComplianceReporter.js +55 -43
- package/lib/service/guard/ExclusionManager.js +67 -29
- package/lib/service/guard/GuardCheckEngine.js +381 -86
- package/lib/service/guard/GuardFeedbackLoop.js +22 -10
- package/lib/service/guard/GuardService.js +29 -19
- package/lib/service/guard/RuleLearner.js +55 -23
- package/lib/service/guard/SourceFileCollector.js +27 -20
- package/lib/service/guard/ViolationsStore.js +43 -38
- package/lib/service/knowledge/CodeEntityGraph.js +147 -82
- package/lib/service/knowledge/ConfidenceRouter.js +12 -10
- package/lib/service/knowledge/KnowledgeFileWriter.js +147 -56
- package/lib/service/knowledge/KnowledgeGraphService.js +81 -34
- package/lib/service/knowledge/KnowledgeService.js +222 -112
- package/lib/service/module/ModuleService.js +969 -0
- package/lib/service/quality/FeedbackCollector.js +27 -15
- package/lib/service/quality/QualityScorer.js +78 -24
- package/lib/service/recipe/RecipeCandidateValidator.js +110 -44
- package/lib/service/recipe/RecipeParser.js +78 -45
- package/lib/service/search/CoarseRanker.js +43 -28
- package/lib/service/search/CrossEncoderReranker.js +32 -21
- package/lib/service/search/InvertedIndex.js +21 -7
- package/lib/service/search/MultiSignalRanker.js +90 -28
- package/lib/service/search/RetrievalFunnel.js +45 -24
- package/lib/service/search/SearchEngine.js +255 -103
- package/lib/service/skills/EventAggregator.js +32 -15
- package/lib/service/skills/SignalCollector.js +140 -64
- package/lib/service/skills/SkillAdvisor.js +79 -42
- package/lib/service/skills/SkillHooks.js +16 -14
- package/lib/service/snippet/PlaceholderConverter.js +5 -0
- package/lib/service/snippet/SnippetFactory.js +116 -99
- package/lib/service/snippet/SnippetInstaller.js +234 -62
- package/lib/service/snippet/codecs/SnippetCodec.js +67 -0
- package/lib/service/snippet/codecs/VSCodeCodec.js +102 -0
- package/lib/service/snippet/codecs/XcodeCodec.js +5 -0
- package/lib/service/wiki/WikiGenerator.js +637 -263
- package/lib/shared/DimensionCopyRegistry.js +472 -0
- package/lib/shared/LanguageService.js +399 -0
- package/lib/shared/PathGuard.js +45 -28
- package/lib/shared/RecipeReadinessChecker.js +72 -12
- package/lib/shared/constants.js +41 -41
- package/lib/shared/errors/BaseError.js +2 -2
- package/lib/shared/errors/index.js +4 -4
- package/lib/shared/similarity.js +25 -8
- package/lib/shared/token-utils.js +6 -2
- package/lib/shared/utils/common.js +12 -4
- package/package.json +49 -13
- package/scripts/bench-real-projects.mjs +256 -0
- package/scripts/build-native-ui.js +30 -30
- package/scripts/clear-old-vector-index.js +5 -35
- package/scripts/clear-vector-cache.js +7 -37
- package/scripts/collect-test-project-stats.mjs +160 -0
- package/scripts/diagnose-mcp.js +41 -32
- package/scripts/ensure-parse-package.js +6 -9
- package/scripts/generate-recipe-drafts.js +116 -77
- package/scripts/init-db.js +3 -20
- package/scripts/init-snippets.js +305 -0
- package/scripts/init-vector-db.js +173 -170
- package/scripts/install-cursor-skill.js +148 -104
- package/scripts/install-full.js +8 -21
- package/scripts/install-vscode-copilot.js +146 -145
- package/scripts/migrate-md-to-knowledge.mjs +139 -151
- package/scripts/postinstall-safe.js +5 -17
- package/scripts/recipe-audit.js +106 -82
- package/scripts/release.js +283 -323
- package/scripts/setup-mcp-config.js +60 -52
- package/scripts/verify-context-api.js +20 -20
- package/skills/autosnippet-analysis/SKILL.md +10 -6
- package/skills/autosnippet-candidates/SKILL.md +27 -26
- package/skills/autosnippet-coldstart/SKILL.md +555 -38
- package/skills/autosnippet-concepts/SKILL.md +349 -337
- package/skills/autosnippet-create/SKILL.md +5 -5
- package/skills/autosnippet-reference-dart/SKILL.md +543 -0
- package/skills/autosnippet-reference-go/SKILL.md +539 -0
- package/skills/autosnippet-reference-java/SKILL.md +534 -0
- package/skills/autosnippet-reference-jsts/SKILL.md +41 -9
- package/skills/autosnippet-reference-kotlin/SKILL.md +526 -0
- package/skills/autosnippet-reference-objc/SKILL.md +29 -6
- package/skills/autosnippet-reference-python/SKILL.md +800 -0
- package/skills/autosnippet-reference-swift/SKILL.md +70 -14
- package/skills/autosnippet-structure/SKILL.md +4 -4
- package/templates/cursor-rules/autosnippet-conventions.mdc +2 -2
- package/templates/recipes-setup/README.md +2 -2
- package/templates/recipes-setup/_template.md +1 -1
- package/dashboard/dist/assets/index-Bun3ld_J.css +0 -1
- package/dashboard/dist/assets/index-_Sk_Dmg3.js +0 -143
- package/resources/asd-entry/main.swift +0 -159
- package/scripts/build-asd-entry.js +0 -51
- package/scripts/init-xcode-snippets.js +0 -311
- package/template.json +0 -39
|
@@ -13,9 +13,10 @@
|
|
|
13
13
|
* - 构建后只读
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
import fs from 'node:fs';
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
import { LanguageService } from '../../shared/LanguageService.js';
|
|
16
19
|
import { analyzeFile, isAvailable } from '../AstAnalyzer.js';
|
|
17
|
-
import fs from 'fs';
|
|
18
|
-
import path from 'path';
|
|
19
20
|
|
|
20
21
|
// ──────────────────────────────────────────────────────────────────
|
|
21
22
|
// 默认配置
|
|
@@ -23,15 +24,44 @@ import path from 'path';
|
|
|
23
24
|
|
|
24
25
|
const DEFAULTS = {
|
|
25
26
|
maxFiles: 500,
|
|
26
|
-
maxFileSizeBytes: 500_000,
|
|
27
|
+
maxFileSizeBytes: 500_000, // 500KB — 跳过超大文件
|
|
27
28
|
excludePatterns: [
|
|
28
|
-
|
|
29
|
-
'
|
|
29
|
+
// 通用
|
|
30
|
+
'node_modules/',
|
|
31
|
+
'.build/',
|
|
32
|
+
'build/',
|
|
33
|
+
'.git/',
|
|
34
|
+
'dist/',
|
|
35
|
+
'out/',
|
|
36
|
+
// iOS
|
|
37
|
+
'Pods/',
|
|
38
|
+
'Carthage/',
|
|
39
|
+
'DerivedData/',
|
|
40
|
+
// Python
|
|
41
|
+
'__pycache__/',
|
|
42
|
+
'.venv/',
|
|
43
|
+
'venv/',
|
|
44
|
+
'.tox/',
|
|
45
|
+
'*.egg-info/',
|
|
46
|
+
// JVM
|
|
47
|
+
'target/',
|
|
48
|
+
'.gradle/',
|
|
49
|
+
'.idea/',
|
|
50
|
+
// Test
|
|
51
|
+
'__tests__/',
|
|
52
|
+
'Tests/',
|
|
53
|
+
'test/',
|
|
54
|
+
'tests/',
|
|
55
|
+
// Dart / Flutter
|
|
56
|
+
'.dart_tool/',
|
|
57
|
+
'.fvm/',
|
|
58
|
+
// Misc
|
|
59
|
+
'vendor/',
|
|
30
60
|
],
|
|
61
|
+
// 从 LanguageService 派生,仅覆盖 AST 解析需要区分 tsx 的场景
|
|
31
62
|
extensionToLang: {
|
|
32
|
-
|
|
33
|
-
'.
|
|
34
|
-
'.swift': 'swift',
|
|
63
|
+
...LanguageService.extToLangMap,
|
|
64
|
+
'.tsx': 'tsx', // tree-sitter 需要独立的 tsx 解析器
|
|
35
65
|
},
|
|
36
66
|
};
|
|
37
67
|
|
|
@@ -40,7 +70,6 @@ const DEFAULTS = {
|
|
|
40
70
|
// ──────────────────────────────────────────────────────────────────
|
|
41
71
|
|
|
42
72
|
export default class ProjectGraph {
|
|
43
|
-
|
|
44
73
|
/** @type {Map<string, ClassInfo>} */
|
|
45
74
|
#classes = new Map();
|
|
46
75
|
|
|
@@ -94,9 +123,7 @@ export default class ProjectGraph {
|
|
|
94
123
|
|
|
95
124
|
// 1. 收集文件列表
|
|
96
125
|
const extToLang = opts.extensionToLang || DEFAULTS.extensionToLang;
|
|
97
|
-
const extensions = options.extensions
|
|
98
|
-
? options.extensions
|
|
99
|
-
: Object.keys(extToLang);
|
|
126
|
+
const extensions = options.extensions ? options.extensions : Object.keys(extToLang);
|
|
100
127
|
|
|
101
128
|
const files = collectSourceFiles(projectRoot, extensions, opts);
|
|
102
129
|
|
|
@@ -106,7 +133,7 @@ export default class ProjectGraph {
|
|
|
106
133
|
let parsed = 0;
|
|
107
134
|
|
|
108
135
|
for (const filePath of files) {
|
|
109
|
-
if (opts.timeoutMs &&
|
|
136
|
+
if (opts.timeoutMs && Date.now() - startTime > opts.timeoutMs) {
|
|
110
137
|
break; // 超时 — 返回部分结果
|
|
111
138
|
}
|
|
112
139
|
|
|
@@ -114,11 +141,15 @@ export default class ProjectGraph {
|
|
|
114
141
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
115
142
|
const ext = path.extname(filePath);
|
|
116
143
|
const lang = extToLang[ext];
|
|
117
|
-
if (!lang)
|
|
144
|
+
if (!lang) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
118
147
|
|
|
119
148
|
const relativePath = path.relative(projectRoot, filePath);
|
|
120
149
|
const summary = analyzeFile(content, lang);
|
|
121
|
-
if (!summary)
|
|
150
|
+
if (!summary) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
122
153
|
|
|
123
154
|
graph.#indexFileSummary(relativePath, summary);
|
|
124
155
|
parsed++;
|
|
@@ -180,7 +211,9 @@ export default class ProjectGraph {
|
|
|
180
211
|
getSubclasses(className) {
|
|
181
212
|
const subs = [];
|
|
182
213
|
for (const [child, parent] of this.#inheritance) {
|
|
183
|
-
if (parent === className)
|
|
214
|
+
if (parent === className) {
|
|
215
|
+
subs.push(child);
|
|
216
|
+
}
|
|
184
217
|
}
|
|
185
218
|
return subs;
|
|
186
219
|
}
|
|
@@ -196,7 +229,9 @@ export default class ProjectGraph {
|
|
|
196
229
|
const visited = new Set();
|
|
197
230
|
while (queue.length > 0) {
|
|
198
231
|
const current = queue.shift();
|
|
199
|
-
if (visited.has(current))
|
|
232
|
+
if (visited.has(current)) {
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
200
235
|
visited.add(current);
|
|
201
236
|
const subs = this.getSubclasses(current);
|
|
202
237
|
result.push(...subs);
|
|
@@ -226,9 +261,7 @@ export default class ProjectGraph {
|
|
|
226
261
|
|
|
227
262
|
for (const desc of descendants) {
|
|
228
263
|
const methods = this.#methodsByClass.get(desc) || [];
|
|
229
|
-
const match = methods.find(m =>
|
|
230
|
-
m.name === methodName || m.selector === methodName
|
|
231
|
-
);
|
|
264
|
+
const match = methods.find((m) => m.name === methodName || m.selector === methodName);
|
|
232
265
|
if (match) {
|
|
233
266
|
overrides.push({
|
|
234
267
|
className: desc,
|
|
@@ -271,7 +304,9 @@ export default class ProjectGraph {
|
|
|
271
304
|
for (const name of this.#classes.keys()) {
|
|
272
305
|
if (name.toLowerCase().includes(lower)) {
|
|
273
306
|
results.push(name);
|
|
274
|
-
if (results.length >= limit)
|
|
307
|
+
if (results.length >= limit) {
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
275
310
|
}
|
|
276
311
|
}
|
|
277
312
|
return results;
|
|
@@ -282,7 +317,9 @@ export default class ProjectGraph {
|
|
|
282
317
|
* @returns {ProjectOverview}
|
|
283
318
|
*/
|
|
284
319
|
getOverview() {
|
|
285
|
-
if (this.#overview)
|
|
320
|
+
if (this.#overview) {
|
|
321
|
+
return this.#overview;
|
|
322
|
+
}
|
|
286
323
|
|
|
287
324
|
// 按模块 (顶层目录) 统计
|
|
288
325
|
const classesPerModule = {};
|
|
@@ -294,7 +331,9 @@ export default class ProjectGraph {
|
|
|
294
331
|
const module = parts.length > 1 ? parts[0] : '(root)';
|
|
295
332
|
topModules.add(module);
|
|
296
333
|
|
|
297
|
-
if (!classesPerModule[module])
|
|
334
|
+
if (!classesPerModule[module]) {
|
|
335
|
+
classesPerModule[module] = 0;
|
|
336
|
+
}
|
|
298
337
|
classesPerModule[module] += symbols.classes.length;
|
|
299
338
|
|
|
300
339
|
// 入口点检测
|
|
@@ -365,7 +404,7 @@ export default class ProjectGraph {
|
|
|
365
404
|
};
|
|
366
405
|
|
|
367
406
|
// 收集该类的属性
|
|
368
|
-
for (const prop of
|
|
407
|
+
for (const prop of summary.properties || []) {
|
|
369
408
|
if (prop.className === cls.name) {
|
|
370
409
|
classInfo.properties.push({
|
|
371
410
|
name: prop.name,
|
|
@@ -378,7 +417,7 @@ export default class ProjectGraph {
|
|
|
378
417
|
|
|
379
418
|
// 收集该类的方法 (声明 + 定义去重)
|
|
380
419
|
const methodSet = new Set();
|
|
381
|
-
for (const m of
|
|
420
|
+
for (const m of summary.methods || []) {
|
|
382
421
|
if (m.className === cls.name) {
|
|
383
422
|
const key = `${m.isClassMethod ? '+' : '-'}${m.name}`;
|
|
384
423
|
if (!methodSet.has(key)) {
|
|
@@ -429,7 +468,7 @@ export default class ProjectGraph {
|
|
|
429
468
|
conformers: [], // 稍后在 buildReverseIndices 中填充
|
|
430
469
|
};
|
|
431
470
|
|
|
432
|
-
for (const m of
|
|
471
|
+
for (const m of proto.methods || []) {
|
|
433
472
|
const methodInfo = {
|
|
434
473
|
name: m.name,
|
|
435
474
|
selector: m.selector || m.name,
|
|
@@ -456,7 +495,7 @@ export default class ProjectGraph {
|
|
|
456
495
|
categoryName: cat.categoryName || 'ext',
|
|
457
496
|
filePath: relativePath,
|
|
458
497
|
line: cat.line,
|
|
459
|
-
methods: (cat.methods || []).map(m => ({
|
|
498
|
+
methods: (cat.methods || []).map((m) => ({
|
|
460
499
|
name: m.name,
|
|
461
500
|
selector: m.selector || m.name,
|
|
462
501
|
line: m.line,
|
|
@@ -488,8 +527,10 @@ export default class ProjectGraph {
|
|
|
488
527
|
}
|
|
489
528
|
|
|
490
529
|
// 索引方法 (按类名分组)
|
|
491
|
-
for (const m of
|
|
492
|
-
if (!m.className)
|
|
530
|
+
for (const m of summary.methods || []) {
|
|
531
|
+
if (!m.className) {
|
|
532
|
+
continue;
|
|
533
|
+
}
|
|
493
534
|
if (!this.#methodsByClass.has(m.className)) {
|
|
494
535
|
this.#methodsByClass.set(m.className, []);
|
|
495
536
|
}
|
|
@@ -527,7 +568,9 @@ export default class ProjectGraph {
|
|
|
527
568
|
for (const [className, classInfo] of this.#classes) {
|
|
528
569
|
const allMethods = this.#methodsByClass.get(className) || [];
|
|
529
570
|
// 只补充 classInfo.methods 中没有的方法
|
|
530
|
-
const existingNames = new Set(
|
|
571
|
+
const existingNames = new Set(
|
|
572
|
+
classInfo.methods.map((m) => `${m.isClassMethod ? '+' : '-'}${m.name}`)
|
|
573
|
+
);
|
|
531
574
|
for (const m of allMethods) {
|
|
532
575
|
const key = `${m.isClassMethod ? '+' : '-'}${m.name}`;
|
|
533
576
|
if (!existingNames.has(key)) {
|
|
@@ -548,7 +591,9 @@ export default class ProjectGraph {
|
|
|
548
591
|
const mapToObj = (map) => Object.fromEntries(map);
|
|
549
592
|
const mapOfSetsToObj = (map) => {
|
|
550
593
|
const obj = {};
|
|
551
|
-
for (const [k, v] of map)
|
|
594
|
+
for (const [k, v] of map) {
|
|
595
|
+
obj[k] = [...v];
|
|
596
|
+
}
|
|
552
597
|
return obj;
|
|
553
598
|
};
|
|
554
599
|
|
|
@@ -622,10 +667,14 @@ export default class ProjectGraph {
|
|
|
622
667
|
*/
|
|
623
668
|
async incrementalUpdate(changedPaths, deletedPaths = [], options = {}) {
|
|
624
669
|
const { analyzeFile, isAvailable } = await import('../AstAnalyzer.js');
|
|
625
|
-
if (!isAvailable())
|
|
670
|
+
if (!isAvailable()) {
|
|
671
|
+
return { added: 0, updated: 0, deleted: 0 };
|
|
672
|
+
}
|
|
626
673
|
|
|
627
674
|
const extToLang = options.extensionToLang || DEFAULTS.extensionToLang;
|
|
628
|
-
let added = 0,
|
|
675
|
+
let added = 0,
|
|
676
|
+
updated = 0,
|
|
677
|
+
deleted = 0;
|
|
629
678
|
|
|
630
679
|
// 1. 删除已移除文件的索引
|
|
631
680
|
for (const relPath of deletedPaths) {
|
|
@@ -656,7 +705,9 @@ export default class ProjectGraph {
|
|
|
656
705
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
657
706
|
const ext = path.extname(filePath);
|
|
658
707
|
const lang = extToLang[ext];
|
|
659
|
-
if (!lang)
|
|
708
|
+
if (!lang) {
|
|
709
|
+
continue;
|
|
710
|
+
}
|
|
660
711
|
|
|
661
712
|
const relativePath = path.relative(this.#projectRoot, filePath);
|
|
662
713
|
const isUpdate = this.#files.has(relativePath);
|
|
@@ -680,7 +731,9 @@ export default class ProjectGraph {
|
|
|
680
731
|
}
|
|
681
732
|
|
|
682
733
|
const summary = analyzeFile(content, lang);
|
|
683
|
-
if (!summary)
|
|
734
|
+
if (!summary) {
|
|
735
|
+
continue;
|
|
736
|
+
}
|
|
684
737
|
|
|
685
738
|
this.#indexFileSummary(relativePath, summary);
|
|
686
739
|
isUpdate ? updated++ : added++;
|
|
@@ -715,7 +768,9 @@ function collectSourceFiles(dir, extensions, opts) {
|
|
|
715
768
|
const extSet = new Set(extensions);
|
|
716
769
|
|
|
717
770
|
function walk(currentDir) {
|
|
718
|
-
if (results.length >= opts.maxFiles)
|
|
771
|
+
if (results.length >= opts.maxFiles) {
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
719
774
|
|
|
720
775
|
let entries;
|
|
721
776
|
try {
|
|
@@ -725,13 +780,15 @@ function collectSourceFiles(dir, extensions, opts) {
|
|
|
725
780
|
}
|
|
726
781
|
|
|
727
782
|
for (const entry of entries) {
|
|
728
|
-
if (results.length >= opts.maxFiles)
|
|
783
|
+
if (results.length >= opts.maxFiles) {
|
|
784
|
+
return;
|
|
785
|
+
}
|
|
729
786
|
|
|
730
787
|
const fullPath = path.join(currentDir, entry.name);
|
|
731
788
|
const relativePath = path.relative(dir, fullPath);
|
|
732
789
|
|
|
733
790
|
// 排除模式检查
|
|
734
|
-
if (opts.excludePatterns.some(p => relativePath.includes(p))) {
|
|
791
|
+
if (opts.excludePatterns.some((p) => relativePath.includes(p))) {
|
|
735
792
|
continue;
|
|
736
793
|
}
|
|
737
794
|
|
|
@@ -739,12 +796,16 @@ function collectSourceFiles(dir, extensions, opts) {
|
|
|
739
796
|
walk(fullPath);
|
|
740
797
|
} else if (entry.isFile()) {
|
|
741
798
|
const ext = path.extname(entry.name);
|
|
742
|
-
if (!extSet.has(ext))
|
|
799
|
+
if (!extSet.has(ext)) {
|
|
800
|
+
continue;
|
|
801
|
+
}
|
|
743
802
|
|
|
744
803
|
// 跳过过大的文件
|
|
745
804
|
try {
|
|
746
805
|
const stat = fs.statSync(fullPath);
|
|
747
|
-
if (stat.size > opts.maxFileSizeBytes)
|
|
806
|
+
if (stat.size > opts.maxFileSizeBytes) {
|
|
807
|
+
continue;
|
|
808
|
+
}
|
|
748
809
|
} catch {
|
|
749
810
|
continue;
|
|
750
811
|
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module ast/ensure-grammars
|
|
3
|
+
* @description 按需安装缺失的 tree-sitter 语法包
|
|
4
|
+
*
|
|
5
|
+
* 在冷启动检测到项目语言后,检查对应 tree-sitter 包是否已安装,
|
|
6
|
+
* 未安装时自动通过 npm install 补装,然后重新加载 AST 插件。
|
|
7
|
+
*
|
|
8
|
+
* 使用方式:
|
|
9
|
+
* import { ensureGrammars } from '../core/ast/ensure-grammars.js';
|
|
10
|
+
* const result = await ensureGrammars(['typescript', 'javascript'], { logger });
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { execFile } from 'node:child_process';
|
|
14
|
+
import { createRequire } from 'node:module';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
17
|
+
import { promisify } from 'node:util';
|
|
18
|
+
import { LanguageService } from '../../shared/LanguageService.js';
|
|
19
|
+
|
|
20
|
+
const execFileAsync = promisify(execFile);
|
|
21
|
+
const require = createRequire(import.meta.url);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 语言 ID → npm 包名映射
|
|
25
|
+
*/
|
|
26
|
+
const LANG_TO_PACKAGE = {
|
|
27
|
+
objectivec: 'tree-sitter-objc',
|
|
28
|
+
swift: 'tree-sitter-swift',
|
|
29
|
+
typescript: 'tree-sitter-typescript',
|
|
30
|
+
tsx: 'tree-sitter-typescript', // tsx 与 typescript 共用同一个包
|
|
31
|
+
javascript: 'tree-sitter-javascript',
|
|
32
|
+
python: 'tree-sitter-python',
|
|
33
|
+
java: 'tree-sitter-java',
|
|
34
|
+
kotlin: 'tree-sitter-kotlin',
|
|
35
|
+
go: 'tree-sitter-go',
|
|
36
|
+
dart: 'tree-sitter-dart',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* package.json 中声明的版本范围(保持和 optionalDependencies 一致)
|
|
41
|
+
*/
|
|
42
|
+
const PACKAGE_VERSIONS = {
|
|
43
|
+
'tree-sitter-objc': '^3.0.2',
|
|
44
|
+
'tree-sitter-swift': '^0.7.1',
|
|
45
|
+
'tree-sitter-typescript': '^0.23.2',
|
|
46
|
+
'tree-sitter-javascript': '^0.23.1',
|
|
47
|
+
'tree-sitter-python': '^0.23.5',
|
|
48
|
+
'tree-sitter-java': '^0.23.4',
|
|
49
|
+
'tree-sitter-kotlin': '^0.3.8',
|
|
50
|
+
'tree-sitter-go': '^0.25.0',
|
|
51
|
+
'tree-sitter-dart': '^1.0.0',
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 检测某个 npm 包是否已安装可用
|
|
56
|
+
*/
|
|
57
|
+
function isPackageInstalled(pkgName) {
|
|
58
|
+
try {
|
|
59
|
+
require.resolve(pkgName);
|
|
60
|
+
return true;
|
|
61
|
+
} catch {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 获取 AutoSnippet 包的安装根目录(npm install 的 cwd)
|
|
68
|
+
*/
|
|
69
|
+
function getPackageRoot() {
|
|
70
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
71
|
+
// lib/core/ast/ensure-grammars.js → 向上 3 级到包根
|
|
72
|
+
return path.resolve(path.dirname(thisFile), '..', '..', '..');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 按需安装缺失的 tree-sitter 语法包
|
|
77
|
+
*
|
|
78
|
+
* @param {string[]} detectedLanguages - 检测到的语言列表 (如 ['typescript', 'javascript', 'python'])
|
|
79
|
+
* @param {object} [options]
|
|
80
|
+
* @param {object} [options.logger] - Logger 实例(可选)
|
|
81
|
+
* @param {number} [options.timeout=60000] - npm install 超时 (ms)
|
|
82
|
+
* @returns {Promise<{installed: string[], skipped: string[], failed: string[], alreadyAvailable: string[]}>}
|
|
83
|
+
*/
|
|
84
|
+
export async function ensureGrammars(detectedLanguages, options = {}) {
|
|
85
|
+
const { logger, timeout = 60_000 } = options;
|
|
86
|
+
|
|
87
|
+
const result = {
|
|
88
|
+
installed: [], // 本次新安装的包
|
|
89
|
+
skipped: [], // 不需要安装(已有)
|
|
90
|
+
failed: [], // 安装失败的包
|
|
91
|
+
alreadyAvailable: [], // 已经可用的语言
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
if (!detectedLanguages || detectedLanguages.length === 0) {
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 1) 去重: 多个语言可能映射到同一个包 (如 typescript + tsx → tree-sitter-typescript)
|
|
99
|
+
const neededPackages = new Map(); // pkgName → [langIds]
|
|
100
|
+
for (const lang of detectedLanguages) {
|
|
101
|
+
const pkg = LANG_TO_PACKAGE[lang];
|
|
102
|
+
if (!pkg) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (!neededPackages.has(pkg)) {
|
|
106
|
+
neededPackages.set(pkg, []);
|
|
107
|
+
}
|
|
108
|
+
neededPackages.get(pkg).push(lang);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 2) 检查哪些已安装
|
|
112
|
+
const toInstall = [];
|
|
113
|
+
for (const [pkg, langs] of neededPackages) {
|
|
114
|
+
if (isPackageInstalled(pkg)) {
|
|
115
|
+
result.skipped.push(pkg);
|
|
116
|
+
result.alreadyAvailable.push(...langs);
|
|
117
|
+
} else {
|
|
118
|
+
toInstall.push(pkg);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (toInstall.length === 0) {
|
|
123
|
+
logger?.info?.('[ensure-grammars] All required grammars already installed');
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// 3) 批量安装缺失的包
|
|
128
|
+
const pkgRoot = getPackageRoot();
|
|
129
|
+
const installArgs = toInstall.map((pkg) => {
|
|
130
|
+
const ver = PACKAGE_VERSIONS[pkg];
|
|
131
|
+
return ver ? `${pkg}@${ver}` : pkg;
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
logger?.info?.(`[ensure-grammars] Installing missing grammars: ${toInstall.join(', ')}`);
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const { stderr } = await execFileAsync(
|
|
138
|
+
'npm',
|
|
139
|
+
['install', '--no-save', '--no-audit', '--no-fund', ...installArgs],
|
|
140
|
+
{
|
|
141
|
+
cwd: pkgRoot,
|
|
142
|
+
timeout,
|
|
143
|
+
env: { ...process.env, NODE_ENV: '' }, // 避免 NODE_ENV=production 跳过 optional
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
if (stderr && !stderr.includes('npm warn')) {
|
|
148
|
+
logger?.warn?.(`[ensure-grammars] npm stderr: ${stderr.slice(0, 200)}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// 4) 逐个验证安装结果
|
|
152
|
+
for (const pkg of toInstall) {
|
|
153
|
+
// 清除 require cache 以便重新检测
|
|
154
|
+
try {
|
|
155
|
+
delete require.cache[require.resolve(pkg)];
|
|
156
|
+
} catch {
|
|
157
|
+
/* not cached */
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (isPackageInstalled(pkg)) {
|
|
161
|
+
result.installed.push(pkg);
|
|
162
|
+
const langs = neededPackages.get(pkg) || [];
|
|
163
|
+
result.alreadyAvailable.push(...langs);
|
|
164
|
+
logger?.info?.(`[ensure-grammars] ✓ ${pkg} installed successfully`);
|
|
165
|
+
} else {
|
|
166
|
+
result.failed.push(pkg);
|
|
167
|
+
logger?.warn?.(
|
|
168
|
+
`[ensure-grammars] ✗ ${pkg} install reported success but package not resolvable`
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
} catch (err) {
|
|
173
|
+
logger?.warn?.(`[ensure-grammars] npm install failed: ${err.message}`);
|
|
174
|
+
// 批量失败 → 逐个重试
|
|
175
|
+
for (const pkg of toInstall) {
|
|
176
|
+
try {
|
|
177
|
+
const ver = PACKAGE_VERSIONS[pkg];
|
|
178
|
+
const spec = ver ? `${pkg}@${ver}` : pkg;
|
|
179
|
+
await execFileAsync('npm', ['install', '--no-save', '--no-audit', '--no-fund', spec], {
|
|
180
|
+
cwd: pkgRoot,
|
|
181
|
+
timeout: timeout / 2,
|
|
182
|
+
});
|
|
183
|
+
if (isPackageInstalled(pkg)) {
|
|
184
|
+
result.installed.push(pkg);
|
|
185
|
+
const langs = neededPackages.get(pkg) || [];
|
|
186
|
+
result.alreadyAvailable.push(...langs);
|
|
187
|
+
logger?.info?.(`[ensure-grammars] ✓ ${pkg} installed (retry)`);
|
|
188
|
+
} else {
|
|
189
|
+
result.failed.push(pkg);
|
|
190
|
+
}
|
|
191
|
+
} catch {
|
|
192
|
+
result.failed.push(pkg);
|
|
193
|
+
logger?.warn?.(`[ensure-grammars] ✗ ${pkg} install failed permanently`);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return result;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* 在安装新包后重新加载 AST 插件
|
|
203
|
+
* 由于 loadPlugins() 是幂等的(_loaded 标志),需要重置标志后重新加载
|
|
204
|
+
*/
|
|
205
|
+
export async function reloadPlugins() {
|
|
206
|
+
// 动态 import 获取模块并重置 _loaded 状态
|
|
207
|
+
const astIndex = await import('./index.js');
|
|
208
|
+
if (typeof astIndex._resetForReload === 'function') {
|
|
209
|
+
astIndex._resetForReload();
|
|
210
|
+
}
|
|
211
|
+
await astIndex.loadPlugins();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* 从文件扩展名统计推断需要的语言列表
|
|
216
|
+
*
|
|
217
|
+
* @param {Record<string, number>} langStats - { swift: 120, m: 80, ts: 200 }
|
|
218
|
+
* @returns {string[]} 需要的语言 ID 列表
|
|
219
|
+
*/
|
|
220
|
+
export function inferLanguagesFromStats(langStats) {
|
|
221
|
+
// 从 LanguageService 派生,仅覆盖 tsx(tree-sitter 需要独立解析器)
|
|
222
|
+
const bareMap = LanguageService.bareExtToLangMap;
|
|
223
|
+
|
|
224
|
+
const langs = new Set();
|
|
225
|
+
for (const ext of Object.keys(langStats)) {
|
|
226
|
+
const lang = ext === 'tsx' ? 'tsx' : bareMap[ext];
|
|
227
|
+
if (lang) {
|
|
228
|
+
langs.add(lang);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return [...langs];
|
|
232
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module ast/index
|
|
3
|
+
* @description 语言 AST 插件自动加载器
|
|
4
|
+
*
|
|
5
|
+
* 按 try/catch 逐个加载每个语言插件并注册到 AstAnalyzer。
|
|
6
|
+
* 缺少对应 tree-sitter 包时静默跳过(优雅降级)。
|
|
7
|
+
*
|
|
8
|
+
* 使用方式:
|
|
9
|
+
* import '../core/ast/index.js'; // 副作用: 注册所有可用语言插件
|
|
10
|
+
*
|
|
11
|
+
* 或按需:
|
|
12
|
+
* import { loadPlugins } from '../core/ast/index.js';
|
|
13
|
+
* await loadPlugins();
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { registerLanguage } from '../AstAnalyzer.js';
|
|
17
|
+
|
|
18
|
+
let _loaded = false;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* 重置加载标志,允许 loadPlugins() 再次执行
|
|
22
|
+
* 仅由 ensure-grammars.js 在安装新包后调用
|
|
23
|
+
*/
|
|
24
|
+
export function _resetForReload() {
|
|
25
|
+
_loaded = false;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 加载并注册所有可用的语言 AST 插件
|
|
30
|
+
* 幂等 — 多次调用只执行一次
|
|
31
|
+
*/
|
|
32
|
+
export async function loadPlugins() {
|
|
33
|
+
if (_loaded) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
_loaded = true;
|
|
37
|
+
|
|
38
|
+
// ObjC
|
|
39
|
+
try {
|
|
40
|
+
const { plugin } = await import('./lang-objc.js');
|
|
41
|
+
registerLanguage('objectivec', plugin);
|
|
42
|
+
} catch {
|
|
43
|
+
/* tree-sitter-objc not installed */
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Swift
|
|
47
|
+
try {
|
|
48
|
+
const { plugin } = await import('./lang-swift.js');
|
|
49
|
+
registerLanguage('swift', plugin);
|
|
50
|
+
} catch {
|
|
51
|
+
/* tree-sitter-swift not installed */
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// TypeScript
|
|
55
|
+
try {
|
|
56
|
+
const { plugin: tsPlugin, tsxPlugin } = await import('./lang-typescript.js');
|
|
57
|
+
registerLanguage('typescript', tsPlugin);
|
|
58
|
+
if (tsxPlugin) {
|
|
59
|
+
registerLanguage('tsx', tsxPlugin);
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
/* tree-sitter-typescript not installed */
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// JavaScript
|
|
66
|
+
try {
|
|
67
|
+
const { plugin } = await import('./lang-javascript.js');
|
|
68
|
+
registerLanguage('javascript', plugin);
|
|
69
|
+
} catch {
|
|
70
|
+
/* tree-sitter-javascript not installed */
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Python
|
|
74
|
+
try {
|
|
75
|
+
const { plugin } = await import('./lang-python.js');
|
|
76
|
+
registerLanguage('python', plugin);
|
|
77
|
+
} catch {
|
|
78
|
+
/* tree-sitter-python not installed */
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Java
|
|
82
|
+
try {
|
|
83
|
+
const { plugin } = await import('./lang-java.js');
|
|
84
|
+
registerLanguage('java', plugin);
|
|
85
|
+
} catch {
|
|
86
|
+
/* tree-sitter-java not installed */
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Kotlin
|
|
90
|
+
try {
|
|
91
|
+
const { plugin } = await import('./lang-kotlin.js');
|
|
92
|
+
registerLanguage('kotlin', plugin);
|
|
93
|
+
} catch {
|
|
94
|
+
/* tree-sitter-kotlin not installed */
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Go
|
|
98
|
+
try {
|
|
99
|
+
const { plugin } = await import('./lang-go.js');
|
|
100
|
+
registerLanguage('go', plugin);
|
|
101
|
+
} catch {
|
|
102
|
+
/* tree-sitter-go not installed */
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Dart
|
|
106
|
+
try {
|
|
107
|
+
const { plugin } = await import('./lang-dart.js');
|
|
108
|
+
registerLanguage('dart', plugin);
|
|
109
|
+
} catch {
|
|
110
|
+
/* tree-sitter-dart not installed */
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// 自动加载(ESM 模块顶层 await)
|
|
115
|
+
await loadPlugins();
|