autosnippet 3.0.6 → 3.0.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.
@@ -13,17 +13,7 @@
13
13
  * 插件注册入口: lib/core/ast/index.js
14
14
  */
15
15
 
16
- import { createRequire } from 'node:module';
17
-
18
- const require = createRequire(import.meta.url);
19
-
20
- let Parser;
21
-
22
- try {
23
- Parser = require('tree-sitter');
24
- } catch {
25
- // 在没有 tree-sitter 的环境中优雅降级
26
- }
16
+ import { getParserClass, isParserReady } from './ast/parser-init.js';
27
17
 
28
18
  // ──────────────────────────────────────────────────────────────────
29
19
  // 插件注册表
@@ -290,7 +280,7 @@ function generateContextForAgent(projectSummary) {
290
280
  * 检查 Tree-sitter 是否可用(至少有一个语言插件注册)
291
281
  */
292
282
  function isAvailable() {
293
- return !!Parser && _langPlugins.size > 0;
283
+ return isParserReady() && _langPlugins.size > 0;
294
284
  }
295
285
 
296
286
  /**
@@ -307,7 +297,8 @@ function supportedLanguages() {
307
297
  const _parserCache = new Map();
308
298
 
309
299
  function _getParser(lang) {
310
- if (!Parser) {
300
+ const ParserClass = getParserClass();
301
+ if (!ParserClass) {
311
302
  return null;
312
303
  }
313
304
  if (_parserCache.has(lang)) {
@@ -324,7 +315,7 @@ function _getParser(lang) {
324
315
  if (!grammar) {
325
316
  return null;
326
317
  }
327
- const parser = new Parser();
318
+ const parser = new ParserClass();
328
319
  parser.setLanguage(grammar);
329
320
  _parserCache.set(lang, parser);
330
321
  return parser;
@@ -1,200 +1,97 @@
1
1
  /**
2
2
  * @module ast/ensure-grammars
3
- * @description 按需安装缺失的 tree-sitter 语法包
3
+ * @description 检查 .wasm 语法文件可用性
4
4
  *
5
- * 在冷启动检测到项目语言后,检查对应 tree-sitter 包是否已安装,
6
- * 未安装时自动通过 npm install 补装,然后重新加载 AST 插件。
5
+ * 迁移至 web-tree-sitter (WASM) 后,不再需要运行时 npm install。
6
+ * 所有 .wasm 文件随包一起发布在 resources/grammars/。
7
+ * 此模块保留旧接口以兼容调用方,但内部逻辑改为检查 .wasm 文件。
7
8
  *
8
9
  * 使用方式:
9
10
  * import { ensureGrammars } from '../core/ast/ensure-grammars.js';
10
11
  * const result = await ensureGrammars(['typescript', 'javascript'], { logger });
11
12
  */
12
13
 
13
- import { execFile } from 'node:child_process';
14
- import { createRequire } from 'node:module';
14
+ import fs from 'node:fs';
15
15
  import path from 'node:path';
16
16
  import { fileURLToPath } from 'node:url';
17
- import { promisify } from 'node:util';
18
17
  import { LanguageService } from '../../shared/LanguageService.js';
19
18
 
20
- const execFileAsync = promisify(execFile);
21
- const require = createRequire(import.meta.url);
19
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
22
20
 
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
- rust: 'tree-sitter-rust',
38
- };
21
+ /** .wasm 文件存放目录 */
22
+ const GRAMMARS_DIR = path.resolve(__dirname, '..', '..', '..', 'resources', 'grammars');
39
23
 
40
24
  /**
41
- * package.json 中声明的版本范围(保持和 optionalDependencies 一致)
25
+ * 语言 ID .wasm 文件名映射
42
26
  */
43
- const PACKAGE_VERSIONS = {
44
- 'tree-sitter-objc': '^3.0.2',
45
- 'tree-sitter-swift': '^0.7.1',
46
- 'tree-sitter-typescript': '^0.23.2',
47
- 'tree-sitter-javascript': '^0.23.1',
48
- 'tree-sitter-python': '^0.23.5',
49
- 'tree-sitter-java': '^0.23.4',
50
- 'tree-sitter-kotlin': '^0.3.8',
51
- 'tree-sitter-go': '^0.25.0',
52
- 'tree-sitter-dart': '^1.0.0',
53
- 'tree-sitter-rust': '^0.23.2',
27
+ const LANG_TO_WASM = {
28
+ objectivec: 'tree-sitter-objc.wasm',
29
+ swift: 'tree-sitter-swift.wasm',
30
+ typescript: 'tree-sitter-typescript.wasm',
31
+ tsx: 'tree-sitter-tsx.wasm',
32
+ javascript: 'tree-sitter-javascript.wasm',
33
+ python: 'tree-sitter-python.wasm',
34
+ java: 'tree-sitter-java.wasm',
35
+ kotlin: 'tree-sitter-kotlin.wasm',
36
+ go: 'tree-sitter-go.wasm',
37
+ dart: 'tree-sitter-dart.wasm',
38
+ rust: 'tree-sitter-rust.wasm',
54
39
  };
55
40
 
56
41
  /**
57
- * 检测某个 npm 包是否已安装可用
42
+ * 检查 .wasm 文件是否存在
58
43
  */
59
- function isPackageInstalled(pkgName) {
60
- try {
61
- require.resolve(pkgName);
62
- return true;
63
- } catch {
64
- return false;
65
- }
44
+ function isWasmAvailable(wasmFileName) {
45
+ return fs.existsSync(path.join(GRAMMARS_DIR, wasmFileName));
66
46
  }
67
47
 
68
48
  /**
69
- * 获取 AutoSnippet 包的安装根目录(npm install 的 cwd)
70
- */
71
- function getPackageRoot() {
72
- const thisFile = fileURLToPath(import.meta.url);
73
- // lib/core/ast/ensure-grammars.js → 向上 3 级到包根
74
- return path.resolve(path.dirname(thisFile), '..', '..', '..');
75
- }
76
-
77
- /**
78
- * 按需安装缺失的 tree-sitter 语法包
49
+ * 检查所需语言的 .wasm 文件是否就绪
50
+ *
51
+ * 保持旧接口签名以兼容 bootstrap 等调用方。
52
+ * WASM 模式下不会执行 npm install —— 文件随包分发。
79
53
  *
80
- * @param {string[]} detectedLanguages - 检测到的语言列表 (如 ['typescript', 'javascript', 'python'])
54
+ * @param {string[]} detectedLanguages - 检测到的语言列表
81
55
  * @param {object} [options]
82
56
  * @param {object} [options.logger] - Logger 实例(可选)
83
- * @param {number} [options.timeout=60000] - npm install 超时 (ms)
84
57
  * @returns {Promise<{installed: string[], skipped: string[], failed: string[], alreadyAvailable: string[]}>}
85
58
  */
86
59
  export async function ensureGrammars(detectedLanguages, options = {}) {
87
- const { logger, timeout = 60_000 } = options;
60
+ const { logger } = options;
88
61
 
89
62
  const result = {
90
- installed: [], // 本次新安装的包
91
- skipped: [], // 不需要安装(已有)
92
- failed: [], // 安装失败的包
93
- alreadyAvailable: [], // 已经可用的语言
63
+ installed: [], // WASM 模式下始终为空(不再运行时安装)
64
+ skipped: [],
65
+ failed: [],
66
+ alreadyAvailable: [],
94
67
  };
95
68
 
96
69
  if (!detectedLanguages || detectedLanguages.length === 0) {
97
70
  return result;
98
71
  }
99
72
 
100
- // 1) 去重: 多个语言可能映射到同一个包 (如 typescript + tsx → tree-sitter-typescript)
101
- const neededPackages = new Map(); // pkgName → [langIds]
102
73
  for (const lang of detectedLanguages) {
103
- const pkg = LANG_TO_PACKAGE[lang];
104
- if (!pkg) {
74
+ const wasmFile = LANG_TO_WASM[lang];
75
+ if (!wasmFile) {
76
+ result.skipped.push(lang);
105
77
  continue;
106
78
  }
107
- if (!neededPackages.has(pkg)) {
108
- neededPackages.set(pkg, []);
109
- }
110
- neededPackages.get(pkg).push(lang);
111
- }
112
79
 
113
- // 2) 检查哪些已安装
114
- const toInstall = [];
115
- for (const [pkg, langs] of neededPackages) {
116
- if (isPackageInstalled(pkg)) {
117
- result.skipped.push(pkg);
118
- result.alreadyAvailable.push(...langs);
80
+ if (isWasmAvailable(wasmFile)) {
81
+ result.alreadyAvailable.push(lang);
119
82
  } else {
120
- toInstall.push(pkg);
83
+ result.failed.push(lang);
84
+ logger?.warn?.(`[ensure-grammars] Missing .wasm file: ${wasmFile} for language "${lang}"`);
121
85
  }
122
86
  }
123
87
 
124
- if (toInstall.length === 0) {
125
- logger?.info?.('[ensure-grammars] All required grammars already installed');
126
- return result;
127
- }
128
-
129
- // 3) 批量安装缺失的包
130
- const pkgRoot = getPackageRoot();
131
- const installArgs = toInstall.map((pkg) => {
132
- const ver = PACKAGE_VERSIONS[pkg];
133
- return ver ? `${pkg}@${ver}` : pkg;
134
- });
135
-
136
- logger?.info?.(`[ensure-grammars] Installing missing grammars: ${toInstall.join(', ')}`);
137
-
138
- try {
139
- const { stderr } = await execFileAsync(
140
- 'npm',
141
- ['install', '--no-save', '--no-audit', '--no-fund', ...installArgs],
142
- {
143
- cwd: pkgRoot,
144
- timeout,
145
- env: { ...process.env, NODE_ENV: '' }, // 避免 NODE_ENV=production 跳过 optional
146
- }
88
+ if (result.failed.length > 0) {
89
+ logger?.warn?.(
90
+ `[ensure-grammars] ${result.failed.length} grammar(s) missing. ` +
91
+ `Expected in: ${GRAMMARS_DIR}`
147
92
  );
148
-
149
- if (stderr && !stderr.includes('npm warn')) {
150
- logger?.warn?.(`[ensure-grammars] npm stderr: ${stderr.slice(0, 200)}`);
151
- }
152
-
153
- // 4) 逐个验证安装结果
154
- for (const pkg of toInstall) {
155
- // 清除 require cache 以便重新检测
156
- try {
157
- delete require.cache[require.resolve(pkg)];
158
- } catch {
159
- /* not cached */
160
- }
161
-
162
- if (isPackageInstalled(pkg)) {
163
- result.installed.push(pkg);
164
- const langs = neededPackages.get(pkg) || [];
165
- result.alreadyAvailable.push(...langs);
166
- logger?.info?.(`[ensure-grammars] ✓ ${pkg} installed successfully`);
167
- } else {
168
- result.failed.push(pkg);
169
- logger?.warn?.(
170
- `[ensure-grammars] ✗ ${pkg} install reported success but package not resolvable`
171
- );
172
- }
173
- }
174
- } catch (err) {
175
- logger?.warn?.(`[ensure-grammars] npm install failed: ${err.message}`);
176
- // 批量失败 → 逐个重试
177
- for (const pkg of toInstall) {
178
- try {
179
- const ver = PACKAGE_VERSIONS[pkg];
180
- const spec = ver ? `${pkg}@${ver}` : pkg;
181
- await execFileAsync('npm', ['install', '--no-save', '--no-audit', '--no-fund', spec], {
182
- cwd: pkgRoot,
183
- timeout: timeout / 2,
184
- });
185
- if (isPackageInstalled(pkg)) {
186
- result.installed.push(pkg);
187
- const langs = neededPackages.get(pkg) || [];
188
- result.alreadyAvailable.push(...langs);
189
- logger?.info?.(`[ensure-grammars] ✓ ${pkg} installed (retry)`);
190
- } else {
191
- result.failed.push(pkg);
192
- }
193
- } catch {
194
- result.failed.push(pkg);
195
- logger?.warn?.(`[ensure-grammars] ✗ ${pkg} install failed permanently`);
196
- }
197
- }
93
+ } else {
94
+ logger?.info?.('[ensure-grammars] All required grammar .wasm files available');
198
95
  }
199
96
 
200
97
  return result;
@@ -205,7 +102,6 @@ export async function ensureGrammars(detectedLanguages, options = {}) {
205
102
  * 由于 loadPlugins() 是幂等的(_loaded 标志),需要重置标志后重新加载
206
103
  */
207
104
  export async function reloadPlugins() {
208
- // 动态 import 获取模块并重置 _loaded 状态
209
105
  const astIndex = await import('./index.js');
210
106
  if (typeof astIndex._resetForReload === 'function') {
211
107
  astIndex._resetForReload();
@@ -220,7 +116,6 @@ export async function reloadPlugins() {
220
116
  * @returns {string[]} 需要的语言 ID 列表
221
117
  */
222
118
  export function inferLanguagesFromStats(langStats) {
223
- // 从 LanguageService 派生,仅覆盖 tsx(tree-sitter 需要独立解析器)
224
119
  const bareMap = LanguageService.bareExtToLangMap;
225
120
 
226
121
  const langs = new Set();
@@ -1,9 +1,15 @@
1
1
  /**
2
2
  * @module ast/index
3
- * @description 语言 AST 插件自动加载器
3
+ * @description 语言 AST 插件自动加载器(web-tree-sitter WASM 版)
4
4
  *
5
- * 按 try/catch 逐个加载每个语言插件并注册到 AstAnalyzer。
6
- * 缺少对应 tree-sitter 包时静默跳过(优雅降级)。
5
+ * 初始化流程:
6
+ * 1. 调用 initParser() — 初始化 web-tree-sitter WASM 运行时
7
+ * 2. 并行加载所有 .wasm 语法文件
8
+ * 3. 将 Language 对象注入每个 lang-*.js 插件
9
+ * 4. 注册到 AstAnalyzer
10
+ *
11
+ * .wasm 文件位于 resources/grammars/,随 npm 包一起发布。
12
+ * 不再依赖原生 tree-sitter 编译,任何平台即装即用。
7
13
  *
8
14
  * 使用方式:
9
15
  * import '../core/ast/index.js'; // 副作用: 注册所有可用语言插件
@@ -14,6 +20,7 @@
14
20
  */
15
21
 
16
22
  import { registerLanguage } from '../AstAnalyzer.js';
23
+ import { initParser, loadLanguageWasm, isParserReady } from './parser-init.js';
17
24
 
18
25
  let _loaded = false;
19
26
 
@@ -25,6 +32,23 @@ export function _resetForReload() {
25
32
  _loaded = false;
26
33
  }
27
34
 
35
+ /**
36
+ * 语言注册表 — langId → { wasmFile, module, setGrammarFn, langId, tsxWasmFile?, setTsxGrammarFn? }
37
+ */
38
+ const LANG_REGISTRY = [
39
+ { langId: 'objectivec', wasmFile: 'tree-sitter-objc.wasm', module: './lang-objc.js', setFn: 'setGrammar' },
40
+ { langId: 'swift', wasmFile: 'tree-sitter-swift.wasm', module: './lang-swift.js', setFn: 'setGrammar' },
41
+ { langId: 'typescript', wasmFile: 'tree-sitter-typescript.wasm', module: './lang-typescript.js', setFn: 'setGrammar' },
42
+ { langId: 'tsx', wasmFile: 'tree-sitter-tsx.wasm', module: './lang-typescript.js', setFn: 'setTsxGrammar', pluginKey: 'tsxPlugin' },
43
+ { langId: 'javascript', wasmFile: 'tree-sitter-javascript.wasm', module: './lang-javascript.js', setFn: 'setGrammar' },
44
+ { langId: 'python', wasmFile: 'tree-sitter-python.wasm', module: './lang-python.js', setFn: 'setGrammar' },
45
+ { langId: 'java', wasmFile: 'tree-sitter-java.wasm', module: './lang-java.js', setFn: 'setGrammar' },
46
+ { langId: 'kotlin', wasmFile: 'tree-sitter-kotlin.wasm', module: './lang-kotlin.js', setFn: 'setGrammar' },
47
+ { langId: 'go', wasmFile: 'tree-sitter-go.wasm', module: './lang-go.js', setFn: 'setGrammar' },
48
+ { langId: 'dart', wasmFile: 'tree-sitter-dart.wasm', module: './lang-dart.js', setFn: 'setGrammar' },
49
+ { langId: 'rust', wasmFile: 'tree-sitter-rust.wasm', module: './lang-rust.js', setFn: 'setGrammar' },
50
+ ];
51
+
28
52
  /**
29
53
  * 加载并注册所有可用的语言 AST 插件
30
54
  * 幂等 — 多次调用只执行一次
@@ -35,87 +59,56 @@ export async function loadPlugins() {
35
59
  }
36
60
  _loaded = true;
37
61
 
38
- // ObjC
39
- try {
40
- const { plugin } = await import('./lang-objc.js');
41
- registerLanguage('objectivec', plugin);
42
- } catch {
43
- /* tree-sitter-objc not installed */
62
+ // 1. 初始化 web-tree-sitter WASM 运行时
63
+ await initParser();
64
+ if (!isParserReady()) {
65
+ return; // web-tree-sitter 不可用,优雅降级(和以前缺少 tree-sitter 一样)
44
66
  }
45
67
 
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);
68
+ // 2. 按顺序加载所有 .wasm 语法文件(并行加载偶发竞态导致失败)
69
+ const wasmResults = [];
70
+ for (const entry of LANG_REGISTRY) {
71
+ try {
72
+ const lang = await loadLanguageWasm(entry.wasmFile);
73
+ wasmResults.push({ status: 'fulfilled', value: lang });
74
+ } catch (err) {
75
+ wasmResults.push({ status: 'rejected', reason: err });
60
76
  }
61
- } catch {
62
- /* tree-sitter-typescript not installed */
63
77
  }
64
78
 
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
- }
79
+ // 3. 逐个加载插件模块并注入 Grammar
80
+ const moduleCache = new Map();
72
81
 
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
- }
82
+ for (let i = 0; i < LANG_REGISTRY.length; i++) {
83
+ const entry = LANG_REGISTRY[i];
84
+ const wasmResult = wasmResults[i];
80
85
 
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
- }
86
+ if (wasmResult.status !== 'fulfilled' || !wasmResult.value) {
87
+ continue; // wasm 加载失败,跳过此语言
88
+ }
88
89
 
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
- }
90
+ const language = wasmResult.value;
96
91
 
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
- }
92
+ try {
93
+ // 模块缓存(TypeScript 模块被 typescript + tsx 共用)
94
+ let mod = moduleCache.get(entry.module);
95
+ if (!mod) {
96
+ mod = await import(entry.module);
97
+ moduleCache.set(entry.module, mod);
98
+ }
104
99
 
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
- }
100
+ // 注入 Grammar
101
+ mod[entry.setFn](language);
112
102
 
113
- // Rust
114
- try {
115
- const { plugin } = await import('./lang-rust.js');
116
- registerLanguage('rust', plugin);
117
- } catch {
118
- /* tree-sitter-rust not installed */
103
+ // 注册到 AstAnalyzer
104
+ const pluginKey = entry.pluginKey || 'plugin';
105
+ const plugin = mod[pluginKey];
106
+ if (plugin) {
107
+ registerLanguage(entry.langId, plugin);
108
+ }
109
+ } catch {
110
+ /* 插件加载失败,静默跳过 */
111
+ }
119
112
  }
120
113
  }
121
114
 
@@ -7,13 +7,9 @@
7
7
  * Builder, BLoC/Cubit, Provider/Riverpod, Freezed
8
8
  *
9
9
  * 注意: tree-sitter-dart 目前尚无兼容 tree-sitter ≥0.25 的稳定版。
10
- * 本插件已实现完整的 walk/detectPatterns 逻辑,等待上游发布兼容版本后即可启用。
10
+ * 已迁移至 web-tree-sitter (WASM),无原生编译依赖。
11
11
  */
12
12
 
13
- import { createRequire } from 'node:module';
14
-
15
- const require = createRequire(import.meta.url);
16
-
17
13
  function walkDart(root, ctx) {
18
14
  _walkNode(root, ctx, null);
19
15
  }
@@ -647,11 +643,11 @@ function _maxNesting(node, depth) {
647
643
 
648
644
  let _grammar = null;
649
645
  function getGrammar() {
650
- if (!_grammar) {
651
- _grammar = require('tree-sitter-dart');
652
- }
653
646
  return _grammar;
654
647
  }
648
+ export function setGrammar(grammar) {
649
+ _grammar = grammar;
650
+ }
655
651
 
656
652
  export const plugin = {
657
653
  getGrammar,
@@ -7,10 +7,6 @@
7
7
  * Goroutine, Channel, Middleware (http.Handler chain)
8
8
  */
9
9
 
10
- import { createRequire } from 'node:module';
11
-
12
- const require = createRequire(import.meta.url);
13
-
14
10
  function walkGo(root, ctx) {
15
11
  for (let i = 0; i < root.namedChildCount; i++) {
16
12
  const child = root.namedChild(i);
@@ -516,11 +512,11 @@ function _maxNesting(node, depth) {
516
512
 
517
513
  let _grammar = null;
518
514
  function getGrammar() {
519
- if (!_grammar) {
520
- _grammar = require('tree-sitter-go');
521
- }
522
515
  return _grammar;
523
516
  }
517
+ export function setGrammar(grammar) {
518
+ _grammar = grammar;
519
+ }
524
520
 
525
521
  export const plugin = {
526
522
  getGrammar,
@@ -6,10 +6,6 @@
6
6
  * 模式: Singleton, Builder, Factory, DI, Stream Pipeline
7
7
  */
8
8
 
9
- import { createRequire } from 'node:module';
10
-
11
- const require = createRequire(import.meta.url);
12
-
13
9
  function walkJava(root, ctx) {
14
10
  _walkJavaNode(root, ctx, null);
15
11
  }
@@ -421,11 +417,11 @@ function _maxNesting(node, depth) {
421
417
 
422
418
  let _grammar = null;
423
419
  function getGrammar() {
424
- if (!_grammar) {
425
- _grammar = require('tree-sitter-java');
426
- }
427
420
  return _grammar;
428
421
  }
422
+ export function setGrammar(grammar) {
423
+ _grammar = grammar;
424
+ }
429
425
 
430
426
  export const plugin = {
431
427
  getGrammar,
@@ -2,13 +2,9 @@
2
2
  * @module lang-javascript
3
3
  * @description JavaScript AST Walker 插件
4
4
  *
5
- * 与 TypeScript walker 共享大部分逻辑,grammar 使用 tree-sitter-javascript
5
+ * 与 TypeScript walker 共享大部分逻辑,grammar 使用 web-tree-sitter (WASM)
6
6
  */
7
7
 
8
- import { createRequire } from 'node:module';
9
-
10
- const require = createRequire(import.meta.url);
11
-
12
8
  // JavaScript walker 与 TypeScript walker 结构相同
13
9
  // 复用 lang-typescript 的 walker 逻辑
14
10
 
@@ -258,11 +254,11 @@ function _maxNesting(node, depth) {
258
254
 
259
255
  let _grammar = null;
260
256
  function getGrammar() {
261
- if (!_grammar) {
262
- _grammar = require('tree-sitter-javascript');
263
- }
264
257
  return _grammar;
265
258
  }
259
+ export function setGrammar(grammar) {
260
+ _grammar = grammar;
261
+ }
266
262
 
267
263
  export const plugin = {
268
264
  getGrammar,
@@ -6,10 +6,6 @@
6
6
  * 模式: Singleton (object), Factory (companion), DSL, Flow, Sealed
7
7
  */
8
8
 
9
- import { createRequire } from 'node:module';
10
-
11
- const require = createRequire(import.meta.url);
12
-
13
9
  function walkKotlin(root, ctx) {
14
10
  _walkKtNode(root, ctx, null);
15
11
  }
@@ -409,11 +405,11 @@ function _maxNesting(node, depth) {
409
405
 
410
406
  let _grammar = null;
411
407
  function getGrammar() {
412
- if (!_grammar) {
413
- _grammar = require('tree-sitter-kotlin');
414
- }
415
408
  return _grammar;
416
409
  }
410
+ export function setGrammar(grammar) {
411
+ _grammar = grammar;
412
+ }
417
413
 
418
414
  export const plugin = {
419
415
  getGrammar,
@@ -3,10 +3,6 @@
3
3
  * @description ObjC AST Walker 插件 — 从 AstAnalyzer.js 迁移
4
4
  */
5
5
 
6
- import { createRequire } from 'node:module';
7
-
8
- const require = createRequire(import.meta.url);
9
-
10
6
  // ── ObjC AST 遍历 ──
11
7
 
12
8
  function walkObjC(root, ctx) {
@@ -374,11 +370,11 @@ function _maxNesting(node, depth) {
374
370
 
375
371
  let _grammar = null;
376
372
  function getGrammar() {
377
- if (!_grammar) {
378
- _grammar = require('tree-sitter-objc');
379
- }
380
373
  return _grammar;
381
374
  }
375
+ export function setGrammar(grammar) {
376
+ _grammar = grammar;
377
+ }
382
378
 
383
379
  export const plugin = {
384
380
  getGrammar,
@@ -6,10 +6,6 @@
6
6
  * 模式: Singleton, Factory, Context Manager, Decorator pattern, Data Class
7
7
  */
8
8
 
9
- import { createRequire } from 'node:module';
10
-
11
- const require = createRequire(import.meta.url);
12
-
13
9
  function walkPython(root, ctx) {
14
10
  _walkPyNode(root, ctx, null);
15
11
  }
@@ -357,11 +353,11 @@ function _maxNesting(node, depth) {
357
353
 
358
354
  let _grammar = null;
359
355
  function getGrammar() {
360
- if (!_grammar) {
361
- _grammar = require('tree-sitter-python');
362
- }
363
356
  return _grammar;
364
357
  }
358
+ export function setGrammar(grammar) {
359
+ _grammar = grammar;
360
+ }
365
361
 
366
362
  export const plugin = {
367
363
  getGrammar,
@@ -7,10 +7,6 @@
7
7
  * Async (tokio/async-std), Unsafe block, Derive macro
8
8
  */
9
9
 
10
- import { createRequire } from 'node:module';
11
-
12
- const require = createRequire(import.meta.url);
13
-
14
10
  function walkRust(root, ctx) {
15
11
  for (let i = 0; i < root.namedChildCount; i++) {
16
12
  const child = root.namedChild(i);
@@ -681,11 +677,11 @@ function _maxNesting(node, depth) {
681
677
 
682
678
  let _grammar = null;
683
679
  function getGrammar() {
684
- if (!_grammar) {
685
- _grammar = require('tree-sitter-rust');
686
- }
687
680
  return _grammar;
688
681
  }
682
+ export function setGrammar(grammar) {
683
+ _grammar = grammar;
684
+ }
689
685
 
690
686
  export const plugin = {
691
687
  getGrammar,
@@ -3,10 +3,6 @@
3
3
  * @description Swift AST Walker 插件 — 从 AstAnalyzer.js 迁移
4
4
  */
5
5
 
6
- import { createRequire } from 'node:module';
7
-
8
- const require = createRequire(import.meta.url);
9
-
10
6
  // ── Swift AST 遍历 ──
11
7
 
12
8
  function walkSwift(root, ctx) {
@@ -323,11 +319,11 @@ function _maxNesting(node, depth) {
323
319
 
324
320
  let _grammar = null;
325
321
  function getGrammar() {
326
- if (!_grammar) {
327
- _grammar = require('tree-sitter-swift');
328
- }
329
322
  return _grammar;
330
323
  }
324
+ export function setGrammar(grammar) {
325
+ _grammar = grammar;
326
+ }
331
327
 
332
328
  export const plugin = {
333
329
  getGrammar,
@@ -6,10 +6,6 @@
6
6
  * 模式检测: Singleton, Factory, Observer, React Hook/Component, Middleware, Decorator
7
7
  */
8
8
 
9
- import { createRequire } from 'node:module';
10
-
11
- const require = createRequire(import.meta.url);
12
-
13
9
  function walkTypeScript(root, ctx) {
14
10
  _walkTSNode(root, ctx, null);
15
11
  }
@@ -471,12 +467,11 @@ function _maxNesting(node, depth) {
471
467
 
472
468
  let _tsGrammar = null;
473
469
  function getGrammar() {
474
- if (!_tsGrammar) {
475
- const ts = require('tree-sitter-typescript');
476
- _tsGrammar = ts.typescript;
477
- }
478
470
  return _tsGrammar;
479
471
  }
472
+ export function setGrammar(grammar) {
473
+ _tsGrammar = grammar;
474
+ }
480
475
 
481
476
  export const plugin = {
482
477
  getGrammar,
@@ -488,12 +483,11 @@ export const plugin = {
488
483
  // TSX 插件 — 共享 walker,不同 grammar
489
484
  let _tsxGrammar = null;
490
485
  function getTsxGrammar() {
491
- if (!_tsxGrammar) {
492
- const ts = require('tree-sitter-typescript');
493
- _tsxGrammar = ts.tsx;
494
- }
495
486
  return _tsxGrammar;
496
487
  }
488
+ export function setTsxGrammar(grammar) {
489
+ _tsxGrammar = grammar;
490
+ }
497
491
 
498
492
  export const tsxPlugin = {
499
493
  getGrammar: getTsxGrammar,
@@ -0,0 +1,82 @@
1
+ /**
2
+ * @module ast/parser-init
3
+ * @description web-tree-sitter 初始化器
4
+ *
5
+ * 统一管理 WASM 版 Parser 的生命周期:
6
+ * 1. 调用 Parser.init() 初始化 WASM 运行时(仅一次)
7
+ * 2. 加载 .wasm 语法文件为 Language 对象
8
+ * 3. 提供同步的 Parser 构造与语言设置 API
9
+ *
10
+ * 所有 async 操作(init + wasm 加载)集中在 loadPlugins() 阶段完成,
11
+ * 下游 analyzeFile / findCallExpressions 等保持同步调用。
12
+ */
13
+
14
+ import { fileURLToPath } from 'node:url';
15
+ import path from 'node:path';
16
+ import { readFile } from 'node:fs/promises';
17
+
18
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
+
20
+ /** 预编译 .wasm 文件存放目录 */
21
+ const GRAMMARS_DIR = path.resolve(__dirname, '..', '..', '..', 'resources', 'grammars');
22
+
23
+ let Parser = null;
24
+ /** web-tree-sitter 模块命名空间 — Language.load 在这里 */
25
+ let _namespace = null;
26
+ let _initialized = false;
27
+
28
+ /**
29
+ * 初始化 web-tree-sitter WASM 运行时
30
+ * 幂等 — 多次调用只执行一次
31
+ */
32
+ export async function initParser() {
33
+ if (_initialized) return;
34
+
35
+ try {
36
+ // web-tree-sitter ESM: 导出 { Parser, Language, ... } 命名空间
37
+ const mod = await import('web-tree-sitter');
38
+ _namespace = mod.default || mod;
39
+ // v0.25 导出 { Parser, Language, ... },需要提取 Parser 类
40
+ Parser = typeof _namespace === 'function' ? _namespace : _namespace.Parser;
41
+ await Parser.init();
42
+ _initialized = true;
43
+ } catch (err) {
44
+ // web-tree-sitter 不可用时优雅降级
45
+ Parser = null;
46
+ _initialized = false;
47
+ }
48
+ }
49
+
50
+ /**
51
+ * 获取 Parser 构造函数
52
+ * @returns {typeof import('web-tree-sitter') | null}
53
+ */
54
+ export function getParserClass() {
55
+ return Parser;
56
+ }
57
+
58
+ /**
59
+ * 检查 parser 是否已初始化
60
+ */
61
+ export function isParserReady() {
62
+ return _initialized && Parser !== null;
63
+ }
64
+
65
+ /**
66
+ * 从 resources/grammars/ 加载指定语言的 .wasm 文件
67
+ * @param {string} wasmFileName — 如 'tree-sitter-javascript.wasm'
68
+ * @returns {Promise<object|null>} Language 对象,失败返回 null
69
+ */
70
+ export async function loadLanguageWasm(wasmFileName) {
71
+ if (!_initialized || !_namespace) return null;
72
+
73
+ const wasmPath = path.join(GRAMMARS_DIR, wasmFileName);
74
+ try {
75
+ // 自行读取 wasm 文件为 Uint8Array,绕过 ESM 下 __require("fs/promises") 的兼容问题
76
+ const buffer = await readFile(wasmPath);
77
+ const Language = _namespace.Language || Parser.Language;
78
+ return await Language.load(new Uint8Array(buffer));
79
+ } catch {
80
+ return null;
81
+ }
82
+ }
@@ -122,6 +122,7 @@ const BUILT_IN_RULES = {
122
122
  languages: ['javascript', 'typescript'],
123
123
  dimension: 'file',
124
124
  category: 'style',
125
+ excludePaths: /(?:^|[\/\\])(?:test|tests|__tests__|spec|__mocks__|mock|mocks|fixtures?)[\/\\]|[\/\\](?:test_|spec_)[^\/\\]*\.(?:js|ts)$|\.(?:test|spec)\.(?:js|ts)$/,
125
126
  },
126
127
  'js-no-console-log': {
127
128
  message: '生产代码应移除 console.log,使用专用日志库',
@@ -130,6 +131,7 @@ const BUILT_IN_RULES = {
130
131
  languages: ['javascript', 'typescript'],
131
132
  dimension: 'file',
132
133
  category: 'style',
134
+ excludePaths: /(?:^|[\/\\])(?:test|tests|__tests__|spec|mock|mocks|__mocks__|scripts|tools|debug)[\/\\]|[\/\\](?:test_|spec_|mock)[^\/\\]*\.(?:js|ts)$|\.(?:test|spec)\.(?:js|ts)$/,
133
135
  },
134
136
  'js-no-debugger': {
135
137
  message: '生产代码中不应包含 debugger 语句',
@@ -267,6 +269,7 @@ const BUILT_IN_RULES = {
267
269
  languages: ['go'],
268
270
  dimension: 'file',
269
271
  category: 'correctness',
272
+ excludePaths: /(?:^|[\/\\])(?:tests?|testdata|_test)[\/\\]|_test\.go$/,
270
273
  },
271
274
  'go-no-init-abuse': {
272
275
  message: 'init() 函数副作用难以追踪,避免在 init 中执行复杂逻辑',
@@ -279,10 +282,11 @@ const BUILT_IN_RULES = {
279
282
  'go-no-global-var': {
280
283
  message: '全局可变变量导致并发安全问题,考虑使用依赖注入',
281
284
  severity: 'info',
282
- pattern: '^var\\s+\\w+\\s+',
285
+ pattern: '^var\\s+(?!_\\s)[a-zA-Z]\\w*\\s+(?!=[^=])',
283
286
  languages: ['go'],
284
287
  dimension: 'file',
285
288
  category: 'style',
289
+ excludePaths: /(?:^|[\/\\])(?:tests?|testdata)[\/\\]|_test\.go$/,
286
290
  },
287
291
 
288
292
  // ══════════════════════════════════════════════════════════
@@ -298,17 +302,18 @@ const BUILT_IN_RULES = {
298
302
  category: 'style',
299
303
  },
300
304
  'dart-avoid-dynamic': {
301
- message: '避免使用 dynamic 类型,使用具体类型或泛型提升类型安全',
305
+ message: '避免直接使用 dynamic 作为变量/参数类型,使用具体类型或泛型提升类型安全',
302
306
  severity: 'warning',
303
- pattern: '\\bdynamic\\b',
307
+ pattern: '(?<!<\\w*,\\s*)(?<!<)\\bdynamic\\b(?!\\s*>)',
304
308
  languages: ['dart'],
305
309
  dimension: 'file',
306
310
  category: 'style',
311
+ fixSuggestion: '使用 Object? 或具体类型替代 dynamic;Map<String, dynamic> 用于 JSON 序列化时可保留',
307
312
  },
308
313
  'dart-no-set-state-after-dispose': {
309
314
  message: 'setState 调用前应检查 mounted 状态,避免 disposed 后调用',
310
- severity: 'warning',
311
- pattern: 'setState\\s*\\(',
315
+ severity: 'info',
316
+ pattern: '(?<!mounted\\)\\s*)setState\\s*\\(',
312
317
  languages: ['dart'],
313
318
  dimension: 'file',
314
319
  category: 'correctness',
@@ -372,7 +377,9 @@ const BUILT_IN_RULES = {
372
377
  dimension: 'file',
373
378
  category: 'correctness',
374
379
  fixSuggestion: '使用 ? 操作符传播错误,或 .unwrap_or_default() / .expect("原因")',
375
- excludePaths: /(?:^|[\/\\])tests?[\/\\]|[\/\\]test_|_test\.rs$|[\/\\]benches[\/\\]/,
380
+ excludePaths: /(?:^|[\/\\])(?:tests?|test_helpers|benches|examples)[\/\\]|[\/\\]test_[^\/\\]*\.rs$|_test\.rs$/,
381
+ skipComments: true,
382
+ skipTestBlocks: true,
376
383
  },
377
384
  'rust-no-expect-without-msg': {
378
385
  message: 'expect() 应提供有意义的错误消息,帮助定位 panic 原因',
@@ -399,7 +406,9 @@ const BUILT_IN_RULES = {
399
406
  languages: ['rust'],
400
407
  dimension: 'file',
401
408
  category: 'correctness',
402
- excludePaths: /(?:^|[\/\\])tests?[\/\\]|[\/\\]examples[\/\\]/,
409
+ excludePaths: /(?:^|[\/\\])(?:tests?|test_helpers|benches|examples)[\/\\]|_test\.rs$/,
410
+ skipComments: true,
411
+ skipTestBlocks: true,
403
412
  },
404
413
  'rust-clone-overuse': {
405
414
  message: '频繁 .clone() 可能暗示所有权设计问题,考虑使用借用或 Cow',
@@ -409,6 +418,9 @@ const BUILT_IN_RULES = {
409
418
  dimension: 'file',
410
419
  category: 'performance',
411
420
  fixSuggestion: '分析是否可用 &T 借用替代,或使用 Cow<T> 延迟克隆',
421
+ excludePaths: /(?:^|[\/\\])(?:tests?|test_helpers|benches|examples)[\/\\]|_test\.rs$/,
422
+ skipComments: true,
423
+ skipTestBlocks: true,
412
424
  },
413
425
  'rust-no-panic-in-lib': {
414
426
  message: 'panic!() 在库代码中应避免使用,返回 Result 让调用方决定如何处理',
@@ -417,7 +429,9 @@ const BUILT_IN_RULES = {
417
429
  languages: ['rust'],
418
430
  dimension: 'file',
419
431
  category: 'correctness',
420
- excludePaths: /(?:^|[\/\\])tests?[\/\\]|[\/\\]benches[\/\\]|main\.rs$/,
432
+ excludePaths: /(?:^|[\/\\])(?:tests?|test_helpers|benches|examples)[\/\\]|main\.rs$/,
433
+ skipComments: true,
434
+ skipTestBlocks: true,
421
435
  },
422
436
  'rust-std-mutex-in-async': {
423
437
  message: 'async 代码中不应使用 std::sync::Mutex,MutexGuard 不是 Send',
@@ -589,6 +603,8 @@ export class GuardCheckEngine {
589
603
  type: 'regex',
590
604
  fixSuggestion: rule.fixSuggestion || null,
591
605
  ...(rule.excludePaths ? { excludePaths: rule.excludePaths } : {}),
606
+ ...(rule.skipComments ? { skipComments: true } : {}),
607
+ ...(rule.skipTestBlocks ? { skipTestBlocks: true } : {}),
592
608
  });
593
609
  }
594
610
  }
@@ -655,6 +671,14 @@ export class GuardCheckEngine {
655
671
 
656
672
  const lines = (code || '').split(/\r?\n/);
657
673
 
674
+ // 预计算注释行掩码 — 供 skipComments 规则使用
675
+ // 识别: // 行注释, /// doc, //! inner doc, /* block */, # Python/Shell 行注释
676
+ const commentLines = this._buildCommentMask(lines, language);
677
+
678
+ // 预计算测试块掩码 — 供 skipTestBlocks 规则使用
679
+ // Rust: #[cfg(test)] mod tests { ... } 内联测试模块
680
+ const testBlockLines = this._buildTestBlockMask(lines, language);
681
+
658
682
  for (const rule of rules) {
659
683
  // 跳过空模式或特殊标记 (?!) — 由 code-level 检查接管
660
684
  if (!rule.pattern || rule.pattern === '(?!)') {
@@ -669,7 +693,19 @@ export class GuardCheckEngine {
669
693
  continue;
670
694
  }
671
695
 
696
+ const shouldSkipComments = !!rule.skipComments;
697
+ const shouldSkipTestBlocks = !!rule.skipTestBlocks;
698
+
672
699
  for (let i = 0; i < lines.length; i++) {
700
+ // skipComments: 跳过注释行(doc comments / 行注释 / 块注释内)
701
+ if (shouldSkipComments && commentLines[i]) {
702
+ continue;
703
+ }
704
+ // skipTestBlocks: 跳过内联测试模块(Rust #[cfg(test)] 块等)
705
+ if (shouldSkipTestBlocks && testBlockLines[i]) {
706
+ continue;
707
+ }
708
+
673
709
  if (re.test(lines[i])) {
674
710
  violations.push({
675
711
  ruleId: rule.id || rule.name,
@@ -1179,6 +1215,134 @@ export class GuardCheckEngine {
1179
1215
  return cached;
1180
1216
  }
1181
1217
 
1218
+ /**
1219
+ * 构建内联测试块掩码
1220
+ * 目前支持 Rust #[cfg(test)] mod xxx { ... } 块
1221
+ * @param {string[]} lines
1222
+ * @param {string} language
1223
+ * @returns {boolean[]} 每行是否在测试块内
1224
+ */
1225
+ _buildTestBlockMask(lines, language) {
1226
+ const mask = new Array(lines.length).fill(false);
1227
+
1228
+ // 目前仅 Rust 需要 — #[cfg(test)] 内联测试模块
1229
+ if (language !== 'rust') return mask;
1230
+
1231
+ let inTestBlock = false;
1232
+ let braceDepth = 0;
1233
+
1234
+ for (let i = 0; i < lines.length; i++) {
1235
+ const trimmed = lines[i].trimStart();
1236
+
1237
+ if (!inTestBlock) {
1238
+ // 检测 #[cfg(test)] 属性行
1239
+ if (/^#\[cfg\(test\)\]/.test(trimmed)) {
1240
+ // 向后找 mod xxx { — 标记为测试块起始
1241
+ // 可能在同一行: #[cfg(test)] mod tests {
1242
+ // 也可能在下一行: mod tests {
1243
+ const restOfLine = trimmed.slice('#[cfg(test)]'.length).trim();
1244
+ if (/^mod\s+\w+/.test(restOfLine)) {
1245
+ // 同一行有 mod 声明
1246
+ inTestBlock = true;
1247
+ braceDepth = 0;
1248
+ // 计算本行的花括号
1249
+ for (const ch of lines[i]) {
1250
+ if (ch === '{') braceDepth++;
1251
+ else if (ch === '}') braceDepth--;
1252
+ }
1253
+ mask[i] = true;
1254
+ if (braceDepth <= 0) inTestBlock = false; // 单行 mod 声明 (mod tests;)
1255
+ continue;
1256
+ }
1257
+ // 检查下一行是否是 mod xxx {
1258
+ if (i + 1 < lines.length && /^\s*mod\s+\w+/.test(lines[i + 1])) {
1259
+ mask[i] = true; // #[cfg(test)] 行本身也标记
1260
+ inTestBlock = true;
1261
+ braceDepth = 0;
1262
+ // 下一行会在循环中处理
1263
+ continue;
1264
+ }
1265
+ // 单行 #[cfg(test)] 但后面不是 mod — 不处理
1266
+ }
1267
+ } else {
1268
+ // 正在测试块内 — 追踪花括号深度
1269
+ mask[i] = true;
1270
+ for (const ch of lines[i]) {
1271
+ if (ch === '{') braceDepth++;
1272
+ else if (ch === '}') braceDepth--;
1273
+ }
1274
+ if (braceDepth <= 0) {
1275
+ inTestBlock = false; // 测试块结束
1276
+ }
1277
+ }
1278
+ }
1279
+
1280
+ return mask;
1281
+ }
1282
+
1283
+ /**
1284
+ * 构建注释行掩码 — 识别行注释和块注释内部行
1285
+ *
1286
+ * 支持的注释形式:
1287
+ * // 行注释, /// 文档注释, //! 内部文档注释 (C/Java/JS/TS/Go/Rust/Swift/Kotlin/Dart)
1288
+ * # 行注释 (Python)
1289
+ * /* ... * / 块注释 (C/Java/JS/TS/Go/Rust/Swift/Kotlin)
1290
+ * \"\"\" ... \"\"\" (Python doc-string — 简化: 整行以 \"\"\" 开头的行)
1291
+ *
1292
+ * @param {string[]} lines
1293
+ * @param {string} language
1294
+ * @returns {boolean[]} 每行是否为注释行
1295
+ */
1296
+ _buildCommentMask(lines, language) {
1297
+ const mask = new Array(lines.length).fill(false);
1298
+ let inBlock = false; // 是否在 /* ... */ 块内
1299
+
1300
+ const usesHash = language === 'python'; // Python 用 # 注释
1301
+ const usesSlash = !usesHash; // 其他语言用 //
1302
+
1303
+ for (let i = 0; i < lines.length; i++) {
1304
+ const trimmed = lines[i].trimStart();
1305
+
1306
+ // 块注释延续
1307
+ if (inBlock) {
1308
+ mask[i] = true;
1309
+ if (trimmed.includes('*/')) {
1310
+ inBlock = false;
1311
+ }
1312
+ continue;
1313
+ }
1314
+
1315
+ // 块注释开始(同行不闭合)
1316
+ if (usesSlash && /^\s*\/\*/.test(lines[i])) {
1317
+ mask[i] = true;
1318
+ if (!trimmed.includes('*/')) {
1319
+ inBlock = true;
1320
+ }
1321
+ continue;
1322
+ }
1323
+
1324
+ // 行注释: // 或 /// 或 //!
1325
+ if (usesSlash && /^\s*\/\//.test(lines[i])) {
1326
+ mask[i] = true;
1327
+ continue;
1328
+ }
1329
+
1330
+ // Python 行注释: #
1331
+ if (usesHash && /^\s*#/.test(lines[i])) {
1332
+ mask[i] = true;
1333
+ continue;
1334
+ }
1335
+
1336
+ // Python docstring 行 (简化: 整行以 """ 或 ''' 开头)
1337
+ if (usesHash && /^\s*("""|''')/.test(lines[i])) {
1338
+ mask[i] = true;
1339
+ continue;
1340
+ }
1341
+ }
1342
+
1343
+ return mask;
1344
+ }
1345
+
1182
1346
  /**
1183
1347
  * 获取内置规则列表
1184
1348
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autosnippet",
3
- "version": "3.0.6",
3
+ "version": "3.0.8",
4
4
  "description": "Extract code patterns into a knowledge base for AI coding assistants",
5
5
  "type": "module",
6
6
  "main": "lib/bootstrap.js",
@@ -88,9 +88,9 @@
88
88
  "open": "^8.0.4",
89
89
  "ora": "^8.0.1",
90
90
  "socket.io": "^4.8.1",
91
- "tree-sitter": "^0.25.0",
92
91
  "undici": "^6.23.0",
93
92
  "uuid": "^9.0.1",
93
+ "web-tree-sitter": "^0.25.0",
94
94
  "winston": "^3.11.0",
95
95
  "zod": "^4.3.6"
96
96
  },
@@ -110,7 +110,8 @@
110
110
  "resources/native-ui/combined-window.swift",
111
111
  "resources/native-ui/native-ui",
112
112
  "resources/native-ui/README.md",
113
- "resources/openChrome.applescript"
113
+ "resources/openChrome.applescript",
114
+ "resources/grammars"
114
115
  ],
115
116
  "directories": {
116
117
  "doc": "docs",
@@ -126,45 +127,7 @@
126
127
  "prettier": "^3.1.1",
127
128
  "supertest": "^6.3.3"
128
129
  },
129
- "optionalDependencies": {
130
- "tree-sitter-go": "^0.25.0",
131
- "tree-sitter-java": "^0.23.5",
132
- "tree-sitter-javascript": "^0.25.0",
133
- "tree-sitter-kotlin": "^0.3.8",
134
- "tree-sitter-objc": "^3.0.2",
135
- "tree-sitter-python": "^0.25.0",
136
- "tree-sitter-swift": "^0.7.1",
137
- "tree-sitter-typescript": "^0.23.2",
138
- "tree-sitter-rust": "^0.23.2"
139
- },
140
130
  "overrides": {
141
- "tree-sitter-kotlin": {
142
- "tree-sitter": "$tree-sitter"
143
- },
144
- "tree-sitter-java": {
145
- "tree-sitter": "$tree-sitter"
146
- },
147
- "tree-sitter-python": {
148
- "tree-sitter": "$tree-sitter"
149
- },
150
- "tree-sitter-javascript": {
151
- "tree-sitter": "$tree-sitter"
152
- },
153
- "tree-sitter-typescript": {
154
- "tree-sitter": "$tree-sitter"
155
- },
156
- "tree-sitter-swift": {
157
- "tree-sitter": "$tree-sitter"
158
- },
159
- "tree-sitter-objc": {
160
- "tree-sitter": "$tree-sitter"
161
- },
162
- "tree-sitter-rust": {
163
- "tree-sitter": "$tree-sitter"
164
- },
165
- "tree-sitter-c": {
166
- "tree-sitter": "$tree-sitter"
167
- },
168
131
  "minimatch": "^10.2.2",
169
132
  "diff": "^8.0.3",
170
133
  "glob": "^11.0.0"