@aiderdesk/tree-sitter-utils 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +151 -0
  2. package/dist/cache-manager.d.ts +16 -0
  3. package/dist/cache-manager.d.ts.map +1 -0
  4. package/dist/constants.d.ts +4 -0
  5. package/dist/constants.d.ts.map +1 -0
  6. package/dist/file-utils.d.ts +2 -0
  7. package/dist/file-utils.d.ts.map +1 -0
  8. package/dist/graph-builder.d.ts +13 -0
  9. package/dist/graph-builder.d.ts.map +1 -0
  10. package/dist/index.d.ts +27 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +1070 -0
  13. package/dist/index.js.map +7 -0
  14. package/dist/language-detector.d.ts +5 -0
  15. package/dist/language-detector.d.ts.map +1 -0
  16. package/dist/logger.d.ts +11 -0
  17. package/dist/logger.d.ts.map +1 -0
  18. package/dist/pagerank.d.ts +7 -0
  19. package/dist/pagerank.d.ts.map +1 -0
  20. package/dist/symbol-extractor.d.ts +14 -0
  21. package/dist/symbol-extractor.d.ts.map +1 -0
  22. package/dist/tree-renderer.d.ts +9 -0
  23. package/dist/tree-renderer.d.ts.map +1 -0
  24. package/dist/tree-sitter-analyzer.d.ts +16 -0
  25. package/dist/tree-sitter-analyzer.d.ts.map +1 -0
  26. package/dist/tree-sitter-parser.d.ts +13 -0
  27. package/dist/tree-sitter-parser.d.ts.map +1 -0
  28. package/dist/types.d.ts +57 -0
  29. package/dist/types.d.ts.map +1 -0
  30. package/dist/wasm-downloader.d.ts +7 -0
  31. package/dist/wasm-downloader.d.ts.map +1 -0
  32. package/package.json +62 -0
  33. package/resources/queries/c-tags.scm +9 -0
  34. package/resources/queries/c_sharp-tags.scm +46 -0
  35. package/resources/queries/cpp-tags.scm +15 -0
  36. package/resources/queries/dart-tags.scm +91 -0
  37. package/resources/queries/elisp-tags.scm +8 -0
  38. package/resources/queries/elixir-tags.scm +54 -0
  39. package/resources/queries/elm-tags.scm +19 -0
  40. package/resources/queries/fortran-tags.scm +15 -0
  41. package/resources/queries/go-tags.scm +30 -0
  42. package/resources/queries/haskell-tags.scm +3 -0
  43. package/resources/queries/hcl-tags.scm +77 -0
  44. package/resources/queries/java-tags.scm +20 -0
  45. package/resources/queries/javascript-tags.scm +94 -0
  46. package/resources/queries/julia-tags.scm +60 -0
  47. package/resources/queries/kotlin-tags.scm +27 -0
  48. package/resources/queries/matlab-tags.scm +10 -0
  49. package/resources/queries/ocaml-tags.scm +115 -0
  50. package/resources/queries/ocaml_interface-tags.scm +98 -0
  51. package/resources/queries/php-tags.scm +26 -0
  52. package/resources/queries/python-tags.scm +12 -0
  53. package/resources/queries/ql-tags.scm +26 -0
  54. package/resources/queries/ruby-tags.scm +64 -0
  55. package/resources/queries/rust-tags.scm +60 -0
  56. package/resources/queries/scala-tags.scm +65 -0
  57. package/resources/queries/tsx-tags.scm +51 -0
  58. package/resources/queries/typescript-tags.scm +61 -0
  59. package/resources/queries/zig-tags.scm +3 -0
package/dist/index.js ADDED
@@ -0,0 +1,1070 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
+
33
+ // src/language-detector.ts
34
+ var language_detector_exports = {};
35
+ __export(language_detector_exports, {
36
+ detectLanguage: () => detectLanguage,
37
+ getSupportedExtensions: () => getSupportedExtensions,
38
+ getSupportedLanguages: () => getSupportedLanguages,
39
+ isLanguageSupported: () => isLanguageSupported
40
+ });
41
+ function detectLanguage(filePath) {
42
+ const ext = path.extname(filePath).toLowerCase();
43
+ return LANGUAGE_MAP[ext] || null;
44
+ }
45
+ function isLanguageSupported(filePath) {
46
+ return detectLanguage(filePath) !== null;
47
+ }
48
+ function getSupportedExtensions() {
49
+ return Object.keys(LANGUAGE_MAP);
50
+ }
51
+ function getSupportedLanguages() {
52
+ return [...new Set(Object.values(LANGUAGE_MAP))];
53
+ }
54
+ var path, LANGUAGE_MAP;
55
+ var init_language_detector = __esm({
56
+ "src/language-detector.ts"() {
57
+ "use strict";
58
+ path = __toESM(require("path"));
59
+ LANGUAGE_MAP = {
60
+ ".py": "python",
61
+ ".js": "javascript",
62
+ ".jsx": "javascript",
63
+ ".ts": "typescript",
64
+ ".tsx": "tsx",
65
+ ".mjs": "javascript",
66
+ ".cjs": "javascript",
67
+ ".java": "java",
68
+ ".go": "go",
69
+ ".rs": "rust",
70
+ ".c": "c",
71
+ ".cpp": "cpp",
72
+ ".cc": "cpp",
73
+ ".cxx": "cpp",
74
+ ".h": "c",
75
+ ".hpp": "cpp",
76
+ ".hxx": "cpp",
77
+ ".cs": "c_sharp",
78
+ ".dart": "dart",
79
+ ".hs": "haskell",
80
+ ".lhs": "haskell",
81
+ ".jl": "julia",
82
+ ".ml": "ocaml",
83
+ ".mli": "ocaml_interface",
84
+ ".php": "php",
85
+ ".rb": "ruby",
86
+ ".rake": "ruby",
87
+ ".gemspec": "ruby",
88
+ ".scala": "scala",
89
+ ".sc": "scala"
90
+ };
91
+ }
92
+ });
93
+
94
+ // src/index.ts
95
+ var index_exports = {};
96
+ __export(index_exports, {
97
+ CacheManager: () => CacheManager,
98
+ GraphBuilder: () => GraphBuilder,
99
+ PageRankCalculator: () => PageRankCalculator,
100
+ SymbolExtractor: () => SymbolExtractor,
101
+ TreeRenderer: () => TreeRenderer,
102
+ TreeSitterAnalyzer: () => TreeSitterAnalyzer,
103
+ TreeSitterParser: () => TreeSitterParser,
104
+ detectLanguage: () => detectLanguage,
105
+ downloadWasmForLanguage: () => downloadWasmForLanguage,
106
+ extractSymbols: () => extractSymbols,
107
+ getAllFiles: () => getAllFiles,
108
+ getLanguageWasmConfig: () => getLanguageWasmConfig,
109
+ getLogger: () => getLogger,
110
+ getRepoMap: () => getRepoMap,
111
+ getSupportedExtensions: () => getSupportedExtensions,
112
+ getSupportedLanguages: () => getSupportedLanguages,
113
+ getSupportedLanguagesForWasm: () => getSupportedLanguagesForWasm,
114
+ isLanguageSupported: () => isLanguageSupported,
115
+ setLogger: () => setLogger
116
+ });
117
+ module.exports = __toCommonJS(index_exports);
118
+
119
+ // src/tree-sitter-parser.ts
120
+ var fs2 = __toESM(require("fs/promises"));
121
+ var path4 = __toESM(require("path"));
122
+ var import_web_tree_sitter = require("web-tree-sitter");
123
+ init_language_detector();
124
+
125
+ // src/wasm-downloader.ts
126
+ var fs = __toESM(require("fs/promises"));
127
+ var path2 = __toESM(require("path"));
128
+ var os = __toESM(require("os"));
129
+
130
+ // src/logger.ts
131
+ var defaultLogger = {
132
+ info: (message, ...args) => console.log(`[TreeSitterUtils] ${message}`, ...args),
133
+ warn: (message, ...args) => console.warn(`[TreeSitterUtils] ${message}`, ...args),
134
+ error: (message, ...args) => console.error(`[TreeSitterUtils] ${message}`, ...args),
135
+ debug: (message, ...args) => {
136
+ if (process.env.DEBUG_TREE_SITTER) {
137
+ console.debug(`[TreeSitterUtils] ${message}`, ...args);
138
+ }
139
+ }
140
+ };
141
+ var currentLogger = defaultLogger;
142
+ function setLogger(logger) {
143
+ currentLogger = logger;
144
+ }
145
+ function getLogger() {
146
+ return currentLogger;
147
+ }
148
+ var logger_default = currentLogger;
149
+
150
+ // src/wasm-downloader.ts
151
+ var LANGUAGE_WASM_MAP = {
152
+ python: {
153
+ url: "https://unpkg.com/tree-sitter-python/tree-sitter-python.wasm",
154
+ file: "tree-sitter-python.wasm"
155
+ },
156
+ javascript: {
157
+ url: "https://unpkg.com/tree-sitter-javascript/tree-sitter-javascript.wasm",
158
+ file: "tree-sitter-javascript.wasm"
159
+ },
160
+ typescript: {
161
+ url: "https://unpkg.com/tree-sitter-typescript/tree-sitter-typescript.wasm",
162
+ file: "tree-sitter-typescript.wasm"
163
+ },
164
+ tsx: {
165
+ url: "https://unpkg.com/tree-sitter-typescript/tree-sitter-tsx.wasm",
166
+ file: "tree-sitter-tsx.wasm"
167
+ },
168
+ java: {
169
+ url: "https://unpkg.com/tree-sitter-java/tree-sitter-java.wasm",
170
+ file: "tree-sitter-java.wasm"
171
+ },
172
+ go: {
173
+ url: "https://unpkg.com/tree-sitter-go/tree-sitter-go.wasm",
174
+ file: "tree-sitter-go.wasm"
175
+ },
176
+ rust: {
177
+ url: "https://unpkg.com/tree-sitter-rust/tree-sitter-rust.wasm",
178
+ file: "tree-sitter-rust.wasm"
179
+ },
180
+ c: {
181
+ url: "https://unpkg.com/tree-sitter-c/tree-sitter-c.wasm",
182
+ file: "tree-sitter-c.wasm"
183
+ },
184
+ cpp: {
185
+ url: "https://unpkg.com/tree-sitter-cpp/tree-sitter-cpp.wasm",
186
+ file: "tree-sitter-cpp.wasm"
187
+ },
188
+ ruby: {
189
+ url: "https://unpkg.com/tree-sitter-ruby/tree-sitter-ruby.wasm",
190
+ file: "tree-sitter-ruby.wasm"
191
+ },
192
+ php: {
193
+ url: "https://unpkg.com/tree-sitter-php/tree-sitter-php.wasm",
194
+ file: "tree-sitter-php.wasm"
195
+ },
196
+ scala: {
197
+ url: "https://unpkg.com/tree-sitter-scala/tree-sitter-scala.wasm",
198
+ file: "tree-sitter-scala.wasm"
199
+ },
200
+ dart: {
201
+ url: "https://unpkg.com/tree-sitter-dart/tree-sitter-dart.wasm",
202
+ file: "tree-sitter-dart.wasm"
203
+ },
204
+ ocaml: {
205
+ url: "https://unpkg.com/tree-sitter-ocaml/tree-sitter-ocaml.wasm",
206
+ file: "tree-sitter-ocaml.wasm"
207
+ },
208
+ ocaml_interface: {
209
+ url: "https://unpkg.com/tree-sitter-ocaml/tree-sitter-ocaml_interface.wasm",
210
+ file: "tree-sitter-ocaml_interface.wasm"
211
+ },
212
+ c_sharp: {
213
+ url: "https://unpkg.com/tree-sitter-c-sharp/tree-sitter-c_sharp.wasm",
214
+ file: "tree-sitter-c_sharp.wasm"
215
+ },
216
+ haskell: {
217
+ url: "https://unpkg.com/tree-sitter-haskell/tree-sitter-haskell.wasm",
218
+ file: "tree-sitter-haskell.wasm"
219
+ },
220
+ julia: {
221
+ url: "https://unpkg.com/tree-sitter-julia/tree-sitter-julia.wasm",
222
+ file: "tree-sitter-julia.wasm"
223
+ }
224
+ };
225
+ function getCacheDir() {
226
+ const platform3 = os.platform();
227
+ const homeDir = os.homedir();
228
+ if (platform3 === "darwin") {
229
+ return path2.join(homeDir, "Library", "Caches", "aiderdesk", "tree-sitter");
230
+ } else if (platform3 === "win32") {
231
+ return path2.join(process.env.APPDATA || path2.join(homeDir, "AppData", "Roaming"), "aiderdesk", "tree-sitter");
232
+ } else {
233
+ return path2.join(homeDir, ".cache", "aiderdesk", "tree-sitter");
234
+ }
235
+ }
236
+ async function downloadWasmForLanguage(language) {
237
+ const config = LANGUAGE_WASM_MAP[language];
238
+ if (!config) {
239
+ logger_default.warn(`No WASM configuration for language: ${language}`);
240
+ return null;
241
+ }
242
+ const cacheDir = getCacheDir();
243
+ const wasmPath = path2.join(cacheDir, "wasm", config.file);
244
+ try {
245
+ try {
246
+ const buffer2 = await fs.readFile(wasmPath);
247
+ logger_default.debug(`Loaded WASM for ${language} from cache: ${wasmPath}`);
248
+ return buffer2;
249
+ } catch {
250
+ }
251
+ logger_default.info(`Downloading WASM for ${language} from ${config.url}`);
252
+ const response = await fetch(config.url, { redirect: "follow" });
253
+ if (!response.ok) {
254
+ throw new Error(`Failed to download ${language} WASM: ${response.status} ${response.statusText}`);
255
+ }
256
+ const buffer = Buffer.from(await response.arrayBuffer());
257
+ await fs.mkdir(path2.dirname(wasmPath), { recursive: true });
258
+ await fs.writeFile(wasmPath, buffer);
259
+ logger_default.info(`Downloaded and cached WASM for ${language} (${Math.round(buffer.byteLength / 1024)} KB)`);
260
+ return buffer;
261
+ } catch (error) {
262
+ logger_default.error(`Failed to download WASM for ${language}:`, error);
263
+ return null;
264
+ }
265
+ }
266
+ function getLanguageWasmConfig(language) {
267
+ return LANGUAGE_WASM_MAP[language] || null;
268
+ }
269
+ function getSupportedLanguagesForWasm() {
270
+ return Object.keys(LANGUAGE_WASM_MAP);
271
+ }
272
+
273
+ // src/constants.ts
274
+ var path3 = __toESM(require("path"));
275
+ var import_url = require("url");
276
+ var import_meta = {};
277
+ var getDirname = () => {
278
+ if (typeof __dirname !== "undefined") {
279
+ return __dirname;
280
+ }
281
+ return path3.dirname((0, import_url.fileURLToPath)(import_meta.url));
282
+ };
283
+ var dirName = getDirname();
284
+ var RESOURCES_DIR = path3.join(dirName, "..", "resources");
285
+ var QUERIES_DIR = path3.join(RESOURCES_DIR, "queries");
286
+ var WASM_DIR = path3.join(RESOURCES_DIR, "wasm");
287
+
288
+ // src/tree-sitter-parser.ts
289
+ var TreeSitterParser = class {
290
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
291
+ parser = null;
292
+ languages = /* @__PURE__ */ new Map();
293
+ queries = /* @__PURE__ */ new Map();
294
+ initialized = false;
295
+ async initialize() {
296
+ if (this.initialized) {
297
+ return;
298
+ }
299
+ try {
300
+ await import_web_tree_sitter.Parser.init();
301
+ this.parser = new import_web_tree_sitter.Parser();
302
+ try {
303
+ const queryFiles = await fs2.readdir(QUERIES_DIR);
304
+ for (const file of queryFiles) {
305
+ if (file.endsWith("-tags.scm")) {
306
+ const language = file.replace("-tags.scm", "");
307
+ const queryPath = path4.join(QUERIES_DIR, file);
308
+ const queryContent = await fs2.readFile(queryPath, "utf-8");
309
+ this.queries.set(language, queryContent);
310
+ }
311
+ }
312
+ } catch (error) {
313
+ logger_default.warn("[TreeSitterParser] Could not load query files from resources:", error);
314
+ }
315
+ this.initialized = true;
316
+ logger_default.info(`[TreeSitterParser] Initialized with ${this.queries.size} language queries`);
317
+ } catch (error) {
318
+ logger_default.error("[TreeSitterParser] Initialization failed:", error);
319
+ throw error;
320
+ }
321
+ }
322
+ async loadLanguage(language) {
323
+ if (this.languages.has(language)) {
324
+ return this.languages.get(language);
325
+ }
326
+ try {
327
+ const wasmBuffer = await downloadWasmForLanguage(language);
328
+ if (!wasmBuffer) {
329
+ return null;
330
+ }
331
+ const lang = await import_web_tree_sitter.Language.load(wasmBuffer);
332
+ this.languages.set(language, lang);
333
+ return lang;
334
+ } catch (error) {
335
+ logger_default.error(`[TreeSitterParser] Failed to load language ${language}:`, error);
336
+ return null;
337
+ }
338
+ }
339
+ async parseFile(filePath, rootDir) {
340
+ if (!this.initialized || !this.parser) {
341
+ await this.initialize();
342
+ }
343
+ if (!this.parser) {
344
+ return [];
345
+ }
346
+ const language = detectLanguage(filePath);
347
+ if (!language) {
348
+ return [];
349
+ }
350
+ const lang = await this.loadLanguage(language);
351
+ if (!lang) {
352
+ return [];
353
+ }
354
+ const query = this.queries.get(language);
355
+ if (!query) {
356
+ return [];
357
+ }
358
+ try {
359
+ const sourceCode = await fs2.readFile(filePath, "utf-8");
360
+ this.parser.setLanguage(lang);
361
+ const tree = this.parser.parse(sourceCode);
362
+ if (!tree) {
363
+ return [];
364
+ }
365
+ const tags = this.extractTags(tree.rootNode, query, filePath, lang, rootDir);
366
+ return tags;
367
+ } catch (error) {
368
+ logger_default.error(`[TreeSitterParser] Error parsing file ${filePath}:`, error);
369
+ return [];
370
+ }
371
+ }
372
+ extractTags(node, query, filePath, language, rootDir) {
373
+ const tags = [];
374
+ try {
375
+ const queryObj = new import_web_tree_sitter.Query(language, query);
376
+ const matches = queryObj.matches(node);
377
+ logger_default.debug(`[TreeSitterParser] Found ${matches.length} matches in ${filePath}`);
378
+ const relFname = rootDir ? path4.relative(rootDir, filePath) : filePath;
379
+ for (const match of matches) {
380
+ for (const capture of match.captures) {
381
+ if (!capture.name.startsWith("name.")) {
382
+ continue;
383
+ }
384
+ const name = capture.node.text;
385
+ const kind = this.determineKind(capture.name);
386
+ const line = capture.node.startPosition.row;
387
+ logger_default.debug(`[TreeSitterParser] Found tag: ${name} (${kind}) at line ${line}`);
388
+ tags.push({
389
+ rel_fname: relFname,
390
+ fname: filePath,
391
+ line,
392
+ name,
393
+ kind
394
+ });
395
+ }
396
+ }
397
+ } catch (error) {
398
+ logger_default.error(`[TreeSitterParser] Error extracting tags from ${filePath}:`, error);
399
+ }
400
+ return tags;
401
+ }
402
+ determineKind(captureName) {
403
+ if (captureName.includes("definition")) {
404
+ return "def";
405
+ }
406
+ return "ref";
407
+ }
408
+ };
409
+
410
+ // src/symbol-extractor.ts
411
+ init_language_detector();
412
+ var SymbolExtractor = class {
413
+ constructor(parser) {
414
+ this.parser = parser;
415
+ }
416
+ cacheManager = null;
417
+ setCacheManager(cacheManager) {
418
+ this.cacheManager = cacheManager;
419
+ }
420
+ async extractTags(files, rootDir) {
421
+ const allTags = [];
422
+ const supportedFiles = files.filter(isLanguageSupported);
423
+ logger_default.info(`[SymbolExtractor] Extracting tags from ${supportedFiles.length} supported files out of ${files.length} total`);
424
+ const batchSize = 50;
425
+ for (let i = 0; i < supportedFiles.length; i += batchSize) {
426
+ const batch = supportedFiles.slice(i, i + batchSize);
427
+ const batchTags = await Promise.all(
428
+ batch.map(async (file) => {
429
+ try {
430
+ if (this.cacheManager) {
431
+ const currentMtime = await this.cacheManager.getFileMtime(file);
432
+ if (currentMtime !== null) {
433
+ const cached = await this.cacheManager.getFileCache(file);
434
+ if (cached && cached.mtime === currentMtime) {
435
+ logger_default.debug(`[SymbolExtractor] Cache hit for ${file}`);
436
+ if (rootDir) {
437
+ const path7 = await import("path");
438
+ const relPath = path7.relative(rootDir, file);
439
+ return cached.tags.map((tag) => ({ ...tag, rel_fname: relPath }));
440
+ }
441
+ return cached.tags;
442
+ }
443
+ const tags = await this.parser.parseFile(file, rootDir);
444
+ await this.cacheManager.setFileCache(file, currentMtime, tags);
445
+ return tags;
446
+ }
447
+ }
448
+ return await this.parser.parseFile(file, rootDir);
449
+ } catch (error) {
450
+ logger_default.error(`[SymbolExtractor] Error processing ${file}:`, error);
451
+ return [];
452
+ }
453
+ })
454
+ );
455
+ allTags.push(...batchTags.flat());
456
+ }
457
+ logger_default.info(`[SymbolExtractor] Extracted ${allTags.length} tags total`);
458
+ return allTags;
459
+ }
460
+ filterDefinitions(tags) {
461
+ return tags.filter((tag) => tag.kind === "def");
462
+ }
463
+ filterReferences(tags) {
464
+ return tags.filter((tag) => tag.kind === "ref");
465
+ }
466
+ groupTagsByFile(tags) {
467
+ const grouped = /* @__PURE__ */ new Map();
468
+ for (const tag of tags) {
469
+ const fileTags = grouped.get(tag.rel_fname) || [];
470
+ fileTags.push(tag);
471
+ grouped.set(tag.rel_fname, fileTags);
472
+ }
473
+ return grouped;
474
+ }
475
+ };
476
+
477
+ // src/graph-builder.ts
478
+ var import_graphology = __toESM(require("graphology"));
479
+ var GraphBuilder = class {
480
+ buildDependencyGraph(tags) {
481
+ const graph = new import_graphology.default({ type: "directed", allowSelfLoops: false, multi: true });
482
+ const defines = /* @__PURE__ */ new Map();
483
+ const references = /* @__PURE__ */ new Map();
484
+ const definitions = /* @__PURE__ */ new Map();
485
+ for (const tag of tags) {
486
+ if (tag.kind === "def") {
487
+ if (!defines.has(tag.name)) {
488
+ defines.set(tag.name, /* @__PURE__ */ new Set());
489
+ }
490
+ defines.get(tag.name).add(tag.rel_fname);
491
+ const key = `${tag.rel_fname}:${tag.name}`;
492
+ if (!definitions.has(key)) {
493
+ definitions.set(key, []);
494
+ }
495
+ definitions.get(key).push(tag);
496
+ } else if (tag.kind === "ref") {
497
+ if (!references.has(tag.name)) {
498
+ references.set(tag.name, []);
499
+ }
500
+ references.get(tag.name).push(tag.rel_fname);
501
+ }
502
+ }
503
+ const idents = new Set(Array.from(defines.keys()).filter((k) => references.has(k)));
504
+ for (const ident of Array.from(idents)) {
505
+ const definers = Array.from(defines.get(ident) || []);
506
+ const referencers = references.get(ident) || [];
507
+ let mul = 1;
508
+ if (this.isSnakeCase(ident) || this.isKebabCase(ident) || this.isCamelCase(ident)) {
509
+ mul *= 10;
510
+ }
511
+ if (ident.startsWith("_")) {
512
+ mul *= 0.1;
513
+ }
514
+ if (definers.length > 5) {
515
+ mul *= 0.1;
516
+ }
517
+ const refCounts = /* @__PURE__ */ new Map();
518
+ for (const ref of referencers) {
519
+ refCounts.set(ref, (refCounts.get(ref) || 0) + 1);
520
+ }
521
+ for (const referencer of referencers) {
522
+ const numRefs = refCounts.get(referencer) || 1;
523
+ const weight = mul * Math.sqrt(numRefs);
524
+ for (const definer of definers) {
525
+ if (referencer !== definer) {
526
+ if (!graph.hasNode(referencer)) {
527
+ graph.addNode(referencer);
528
+ }
529
+ if (!graph.hasNode(definer)) {
530
+ graph.addNode(definer);
531
+ }
532
+ const edgeKey = `${referencer}->${definer}:${ident}`;
533
+ if (!graph.hasEdge(edgeKey)) {
534
+ graph.addEdgeWithKey(edgeKey, referencer, definer, { weight, ident });
535
+ }
536
+ }
537
+ }
538
+ }
539
+ }
540
+ logger_default.info(`[GraphBuilder] Built graph with ${graph.order} nodes and ${graph.size} edges`);
541
+ return { graph, defines, references };
542
+ }
543
+ isSnakeCase(str) {
544
+ return /^[a-z][a-z0-9_]*$/.test(str) && str.includes("_");
545
+ }
546
+ isKebabCase(str) {
547
+ return /^[a-z][a-z0-9-]*$/.test(str) && str.includes("-");
548
+ }
549
+ isCamelCase(str) {
550
+ return /^[a-z][a-zA-Z0-9]*$/.test(str) && /[A-Z]/.test(str);
551
+ }
552
+ };
553
+
554
+ // src/pagerank.ts
555
+ var import_pagerank = __toESM(require("graphology-metrics/centrality/pagerank"));
556
+ var PageRankCalculator = class {
557
+ calculate(graph, tags, mentionedFiles, mentionedIdents) {
558
+ if (graph.order === 0) {
559
+ return [];
560
+ }
561
+ const personalization = {};
562
+ const nodes = graph.nodes();
563
+ const personalize = nodes.length > 0 ? 100 / nodes.length : 0;
564
+ for (const node of nodes) {
565
+ let score = 0;
566
+ if (mentionedFiles?.has(node)) {
567
+ score += personalize;
568
+ }
569
+ if (mentionedIdents) {
570
+ const fileTags = tags.filter((t) => t.rel_fname === node && t.kind === "def");
571
+ if (fileTags.some((t) => mentionedIdents.has(t.name))) {
572
+ score += personalize;
573
+ }
574
+ }
575
+ if (score > 0) {
576
+ personalization[node] = score;
577
+ }
578
+ }
579
+ try {
580
+ const pagerankOptions = {
581
+ alpha: 0.85,
582
+ maxIterations: 100,
583
+ tolerance: 1e-6
584
+ };
585
+ if (Object.keys(personalization).length > 0) {
586
+ pagerankOptions.personalization = personalization;
587
+ }
588
+ const ranks = (0, import_pagerank.default)(graph, pagerankOptions);
589
+ const rankedDefinitions = [];
590
+ const definitions = tags.filter((t) => t.kind === "def");
591
+ for (const def of definitions) {
592
+ const nodeRank = ranks[def.rel_fname] || 0;
593
+ let edgeRank = nodeRank;
594
+ if (graph.hasNode(def.rel_fname)) {
595
+ graph.forEachOutboundEdge(def.rel_fname, (edge) => {
596
+ const weight = graph.getEdgeAttribute(edge, "weight");
597
+ const totalWeight = this.getTotalOutboundWeight(graph, def.rel_fname);
598
+ if (totalWeight > 0) {
599
+ edgeRank += nodeRank * (weight / totalWeight);
600
+ }
601
+ });
602
+ }
603
+ rankedDefinitions.push({
604
+ rel_fname: def.rel_fname,
605
+ name: def.name,
606
+ rank: edgeRank,
607
+ line: def.line
608
+ });
609
+ }
610
+ rankedDefinitions.sort((a, b) => b.rank - a.rank);
611
+ logger_default.info(`[PageRankCalculator] Calculated ranks for ${rankedDefinitions.length} definitions`);
612
+ return rankedDefinitions;
613
+ } catch (error) {
614
+ logger_default.error("[PageRankCalculator] Error calculating PageRank:", error);
615
+ return [];
616
+ }
617
+ }
618
+ getTotalOutboundWeight(graph, node) {
619
+ if (!graph.hasNode(node)) {
620
+ return 0;
621
+ }
622
+ let total = 0;
623
+ graph.forEachOutboundEdge(node, (edge) => {
624
+ total += graph.getEdgeAttribute(edge, "weight") || 1;
625
+ });
626
+ return total;
627
+ }
628
+ };
629
+
630
+ // src/tree-renderer.ts
631
+ var fs3 = __toESM(require("fs/promises"));
632
+ var TreeRenderer = class {
633
+ async render(rankedDefinitions, chatFiles, maxLines) {
634
+ const filtered = rankedDefinitions.filter((def) => !chatFiles.has(def.rel_fname));
635
+ const byFile = /* @__PURE__ */ new Map();
636
+ for (const def of filtered) {
637
+ const fileDefs = byFile.get(def.rel_fname) || [];
638
+ fileDefs.push(def);
639
+ byFile.set(def.rel_fname, fileDefs);
640
+ }
641
+ const sortedFiles = Array.from(byFile.entries()).sort((a, b) => {
642
+ const maxRankA = Math.max(...a[1].map((d) => d.rank));
643
+ const maxRankB = Math.max(...b[1].map((d) => d.rank));
644
+ return maxRankB - maxRankA;
645
+ });
646
+ const totalFiles = sortedFiles.length;
647
+ if (!maxLines) {
648
+ return this.renderAllFiles(sortedFiles);
649
+ }
650
+ if (totalFiles > maxLines) {
651
+ return this.renderFileListOnly(sortedFiles, maxLines);
652
+ }
653
+ const headerLines = totalFiles;
654
+ const availableLines = maxLines - headerLines;
655
+ const linesPerFile = Math.max(1, Math.floor(availableLines / totalFiles));
656
+ return this.renderWithLineLimit(sortedFiles, linesPerFile);
657
+ }
658
+ async renderAllFiles(sortedFiles) {
659
+ let output = "";
660
+ for (const [file, definitions] of sortedFiles) {
661
+ output += `
662
+ ${file}:
663
+ `;
664
+ definitions.sort((a, b) => a.line - b.line);
665
+ const lines = Array.from(new Set(definitions.map((d) => d.line)));
666
+ const treeLines = await this.renderFileTree(file, lines, Infinity);
667
+ output += treeLines;
668
+ }
669
+ return output.trim();
670
+ }
671
+ renderFileListOnly(sortedFiles, maxLines) {
672
+ let output = "";
673
+ const filesToShow = sortedFiles.slice(0, maxLines - 1);
674
+ for (const [file] of filesToShow) {
675
+ output += `${file}
676
+ `;
677
+ }
678
+ if (sortedFiles.length > filesToShow.length) {
679
+ output += "...\n";
680
+ }
681
+ return output.trim();
682
+ }
683
+ async renderWithLineLimit(sortedFiles, linesPerFile) {
684
+ let output = "";
685
+ for (const [file, definitions] of sortedFiles) {
686
+ definitions.sort((a, b) => {
687
+ if (a.rank !== b.rank) {
688
+ return b.rank - a.rank;
689
+ }
690
+ return a.line - b.line;
691
+ });
692
+ const uniqueLines = Array.from(new Set(definitions.map((d) => d.line)));
693
+ const limitedLines = uniqueLines.slice(0, linesPerFile);
694
+ const isTruncated = uniqueLines.length > linesPerFile;
695
+ output += `${file}:
696
+ `;
697
+ const treeLines = await this.renderFileTree(file, limitedLines, linesPerFile, isTruncated);
698
+ output += treeLines;
699
+ }
700
+ return output.trim();
701
+ }
702
+ async renderFileTree(filePath, lines, maxLines, isTruncated = false) {
703
+ if (lines.length === 0) {
704
+ return "";
705
+ }
706
+ try {
707
+ const content = await fs3.readFile(filePath, "utf-8");
708
+ const fileLines = content.split("\n");
709
+ let output = "";
710
+ const maxContentLines = isTruncated ? maxLines - 1 : maxLines;
711
+ const linesToRender = lines.slice(0, maxContentLines);
712
+ for (let i = 0; i < linesToRender.length; i++) {
713
+ const lineNum = linesToRender[i];
714
+ const lineContent = fileLines[lineNum]?.trim() || "";
715
+ if (lineContent) {
716
+ const truncated = lineContent.length > 100 ? lineContent.substring(0, 97) + "..." : lineContent;
717
+ const isLast = i === linesToRender.length - 1 && !isTruncated;
718
+ const prefix = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
719
+ output += `${prefix}${truncated}
720
+ `;
721
+ }
722
+ }
723
+ if (isTruncated) {
724
+ output += "\u2514\u2500\u2500 ...\n";
725
+ }
726
+ return output;
727
+ } catch (error) {
728
+ logger_default.error(`[TreeRenderer] Error reading file ${filePath}:`, error);
729
+ return "";
730
+ }
731
+ }
732
+ };
733
+
734
+ // src/cache-manager.ts
735
+ var import_node_sqlite = require("node:sqlite");
736
+ var fs4 = __toESM(require("fs/promises"));
737
+ var path5 = __toESM(require("path"));
738
+ var os2 = __toESM(require("os"));
739
+ function getCacheDbPath() {
740
+ const platform3 = os2.platform();
741
+ const homeDir = os2.homedir();
742
+ let cacheDir;
743
+ if (platform3 === "darwin") {
744
+ cacheDir = path5.join(homeDir, "Library", "Caches", "aiderdesk", "tree-sitter");
745
+ } else if (platform3 === "win32") {
746
+ cacheDir = path5.join(process.env.APPDATA || path5.join(homeDir, "AppData", "Roaming"), "aiderdesk", "tree-sitter");
747
+ } else {
748
+ cacheDir = path5.join(homeDir, ".cache", "aiderdesk", "tree-sitter");
749
+ }
750
+ return path5.join(cacheDir, "cache.db");
751
+ }
752
+ var CacheManager = class {
753
+ db = null;
754
+ dbPath;
755
+ constructor(dbPath) {
756
+ this.dbPath = dbPath || getCacheDbPath();
757
+ }
758
+ async initialize() {
759
+ try {
760
+ await fs4.mkdir(path5.dirname(this.dbPath), { recursive: true });
761
+ this.db = new import_node_sqlite.DatabaseSync(this.dbPath);
762
+ const createTableSQL = `
763
+ CREATE TABLE IF NOT EXISTS file_cache (
764
+ file_path TEXT PRIMARY KEY,
765
+ mtime INTEGER NOT NULL,
766
+ tags TEXT NOT NULL,
767
+ created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
768
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
769
+ )
770
+ `;
771
+ this.db.exec(createTableSQL);
772
+ logger_default.info(`[CacheManager] Cache database initialized at ${this.dbPath}`);
773
+ } catch (error) {
774
+ logger_default.error("[CacheManager] Failed to initialize cache database:", error);
775
+ this.db = null;
776
+ }
777
+ }
778
+ async getFileCache(filePath) {
779
+ if (!this.db) {
780
+ return null;
781
+ }
782
+ try {
783
+ const sql = "SELECT mtime, tags FROM file_cache WHERE file_path = ?";
784
+ const stmt = this.db.prepare(sql);
785
+ const result = stmt.get(filePath);
786
+ if (result) {
787
+ const tags = JSON.parse(result.tags);
788
+ return { tags, mtime: result.mtime };
789
+ }
790
+ return null;
791
+ } catch (error) {
792
+ logger_default.error(`[CacheManager] Failed to get cache for ${filePath}:`, error);
793
+ return null;
794
+ }
795
+ }
796
+ async setFileCache(filePath, mtime, tags) {
797
+ if (!this.db) {
798
+ return;
799
+ }
800
+ try {
801
+ const sql = `
802
+ INSERT INTO file_cache (file_path, mtime, tags, updated_at)
803
+ VALUES (?, ?, ?, CURRENT_TIMESTAMP)
804
+ ON CONFLICT(file_path) DO UPDATE SET
805
+ mtime = excluded.mtime,
806
+ tags = excluded.tags,
807
+ updated_at = CURRENT_TIMESTAMP
808
+ `;
809
+ const stmt = this.db.prepare(sql);
810
+ stmt.run(filePath, mtime, JSON.stringify(tags));
811
+ logger_default.debug(`[CacheManager] Cached ${tags.length} tags for ${filePath}`);
812
+ } catch (error) {
813
+ logger_default.error(`[CacheManager] Failed to set cache for ${filePath}:`, error);
814
+ }
815
+ }
816
+ async getFileMtime(filePath) {
817
+ try {
818
+ const stats = await fs4.stat(filePath);
819
+ return stats.mtimeMs;
820
+ } catch (error) {
821
+ logger_default.error(`[CacheManager] Failed to get mtime for ${filePath}:`, error);
822
+ return null;
823
+ }
824
+ }
825
+ async clearCache() {
826
+ if (!this.db) {
827
+ return;
828
+ }
829
+ try {
830
+ const sql = "DELETE FROM file_cache";
831
+ this.db.exec(sql);
832
+ logger_default.info("[CacheManager] Cache cleared");
833
+ } catch (error) {
834
+ logger_default.error("[CacheManager] Failed to clear cache:", error);
835
+ }
836
+ }
837
+ close() {
838
+ if (this.db) {
839
+ this.db.close();
840
+ this.db = null;
841
+ logger_default.info("[CacheManager] Cache database closed");
842
+ }
843
+ }
844
+ };
845
+
846
+ // src/file-utils.ts
847
+ var path6 = __toESM(require("path"));
848
+ var import_glob = require("glob");
849
+ var import_simple_git = require("simple-git");
850
+ var DEFAULT_IGNORE_PATTERNS = [
851
+ "node_modules/**",
852
+ ".git/**",
853
+ "dist/**",
854
+ "build/**",
855
+ ".next/**",
856
+ "out/**",
857
+ "coverage/**",
858
+ "*.min.js",
859
+ "*.min.css",
860
+ ".DS_Store",
861
+ "Thumbs.db",
862
+ "*.log",
863
+ "*.lock",
864
+ "package-lock.json",
865
+ "yarn.lock",
866
+ "pnpm-lock.yaml"
867
+ ];
868
+ var isGitRepository = async (baseDir) => {
869
+ try {
870
+ const git = (0, import_simple_git.simpleGit)(baseDir);
871
+ await git.revparse(["--git-dir"]);
872
+ return true;
873
+ } catch {
874
+ return false;
875
+ }
876
+ };
877
+ var getAllFilesFromGit = async (baseDir) => {
878
+ try {
879
+ const git = (0, import_simple_git.simpleGit)(baseDir);
880
+ const result = await git.raw(["ls-files", "-z"]);
881
+ const files = result.split("\0").filter(Boolean);
882
+ logger_default.debug(`Retrieved ${files.length} tracked files from Git`);
883
+ return files.map((file) => path6.resolve(baseDir, file));
884
+ } catch (gitError) {
885
+ logger_default.warn("Failed to get tracked files from Git, falling back to filesystem", gitError);
886
+ return [];
887
+ }
888
+ };
889
+ var getAllFilesFromFS = async (baseDir, ignore) => {
890
+ try {
891
+ const pattern = path6.join(baseDir, "**/*").replace(/\\/g, "/");
892
+ const files = await (0, import_glob.glob)(pattern, {
893
+ nodir: true,
894
+ absolute: true,
895
+ dot: false,
896
+ ignore
897
+ });
898
+ logger_default.debug(`Retrieved ${files.length} files from filesystem`);
899
+ return files;
900
+ } catch (error) {
901
+ logger_default.error("Failed to get files from filesystem:", error);
902
+ return [];
903
+ }
904
+ };
905
+ var matchesPattern = (filePath, pattern) => {
906
+ const regexPattern = pattern.replace(/\*\*/g, "<<DOUBLE_STAR>>").replace(/\*/g, "[^/]*").replace(/<<DOUBLE_STAR>>/g, ".*").replace(/\?/g, "[^/]");
907
+ const regex = new RegExp(regexPattern);
908
+ return regex.test(filePath);
909
+ };
910
+ var filterByExcludePatterns = (files, excludePatterns, baseDir) => {
911
+ return files.filter((file) => {
912
+ const relative3 = path6.relative(baseDir, file).replace(/\\/g, "/");
913
+ return !excludePatterns.some((pattern) => matchesPattern(relative3, pattern));
914
+ });
915
+ };
916
+ var getAllFiles = async (baseDir, excludePatterns = []) => {
917
+ const allIgnorePatterns = [...DEFAULT_IGNORE_PATTERNS, ...excludePatterns];
918
+ try {
919
+ if (await isGitRepository(baseDir)) {
920
+ const gitFiles = await getAllFilesFromGit(baseDir);
921
+ if (gitFiles.length > 0) {
922
+ return filterByExcludePatterns(gitFiles, excludePatterns, baseDir);
923
+ }
924
+ }
925
+ const fsFiles = await getAllFilesFromFS(baseDir, allIgnorePatterns);
926
+ return filterByExcludePatterns(fsFiles, excludePatterns, baseDir);
927
+ } catch (error) {
928
+ logger_default.error("Failed to get files:", error);
929
+ return [];
930
+ }
931
+ };
932
+
933
+ // src/tree-sitter-analyzer.ts
934
+ var TreeSitterAnalyzer = class {
935
+ parser;
936
+ symbolExtractor;
937
+ graphBuilder;
938
+ pageRankCalculator;
939
+ treeRenderer;
940
+ cacheManager;
941
+ initialized = false;
942
+ constructor() {
943
+ this.parser = new TreeSitterParser();
944
+ this.cacheManager = new CacheManager();
945
+ this.symbolExtractor = new SymbolExtractor(this.parser);
946
+ this.symbolExtractor.setCacheManager(this.cacheManager);
947
+ this.graphBuilder = new GraphBuilder();
948
+ this.pageRankCalculator = new PageRankCalculator();
949
+ this.treeRenderer = new TreeRenderer();
950
+ }
951
+ async initialize() {
952
+ if (this.initialized) {
953
+ return;
954
+ }
955
+ await this.parser.initialize();
956
+ await this.cacheManager.initialize();
957
+ this.initialized = true;
958
+ logger_default.info("[TreeSitterAnalyzer] Initialized");
959
+ }
960
+ async getRepoMap(options) {
961
+ if (!this.initialized) {
962
+ await this.initialize();
963
+ }
964
+ const { root, files, excludePatterns = [], mentionedFiles = /* @__PURE__ */ new Set(), mentionedIdents = /* @__PURE__ */ new Set(), chatFiles = /* @__PURE__ */ new Set(), maxLines } = options;
965
+ try {
966
+ let filesToProcess;
967
+ if (files && files.length > 0) {
968
+ filesToProcess = files;
969
+ } else {
970
+ filesToProcess = await getAllFiles(root, excludePatterns);
971
+ }
972
+ logger_default.info(`[TreeSitterAnalyzer] Processing ${filesToProcess.length} files for repository map`);
973
+ const tags = await this.symbolExtractor.extractTags(filesToProcess, root);
974
+ if (tags.length === 0) {
975
+ return "";
976
+ }
977
+ const { graph, defines: _defines, references: _references } = this.graphBuilder.buildDependencyGraph(tags);
978
+ const rankedDefinitions = this.pageRankCalculator.calculate(graph, tags, mentionedFiles, mentionedIdents);
979
+ const output = await this.treeRenderer.render(rankedDefinitions, chatFiles, maxLines);
980
+ logger_default.info(`[TreeSitterAnalyzer] Generated repository map with ${rankedDefinitions.length} definitions`);
981
+ return output;
982
+ } catch (error) {
983
+ logger_default.error("[TreeSitterAnalyzer] Error generating repository map:", error);
984
+ return "";
985
+ }
986
+ }
987
+ async extractSymbols(filePaths, options) {
988
+ if (!this.initialized) {
989
+ await this.initialize();
990
+ }
991
+ const useCache = options?.useCache !== false;
992
+ try {
993
+ const originalCacheManager = useCache ? this.cacheManager : null;
994
+ if (!useCache) {
995
+ this.symbolExtractor.setCacheManager(null);
996
+ }
997
+ const tags = await this.symbolExtractor.extractTags(filePaths, options?.rootDir);
998
+ if (!useCache) {
999
+ this.symbolExtractor.setCacheManager(this.cacheManager);
1000
+ }
1001
+ const symbols = tags.map((tag) => ({
1002
+ name: tag.name,
1003
+ kind: tag.kind,
1004
+ line: tag.line,
1005
+ file: tag.fname,
1006
+ relativeFile: tag.rel_fname
1007
+ }));
1008
+ logger_default.info(`[TreeSitterAnalyzer] Extracted ${symbols.length} symbols from ${filePaths.length} files`);
1009
+ return symbols;
1010
+ } catch (error) {
1011
+ logger_default.error("[TreeSitterAnalyzer] Error extracting symbols:", error);
1012
+ return [];
1013
+ }
1014
+ }
1015
+ async parseFile(filePath) {
1016
+ if (!this.initialized) {
1017
+ await this.initialize();
1018
+ }
1019
+ const { detectLanguage: detectLanguage2 } = await Promise.resolve().then(() => (init_language_detector(), language_detector_exports));
1020
+ const language = detectLanguage2(filePath) || "unknown";
1021
+ const tags = await this.parser.parseFile(filePath);
1022
+ return {
1023
+ tags,
1024
+ file: filePath,
1025
+ language
1026
+ };
1027
+ }
1028
+ };
1029
+
1030
+ // src/index.ts
1031
+ init_language_detector();
1032
+ var defaultAnalyzer = null;
1033
+ async function getAnalyzer() {
1034
+ if (!defaultAnalyzer) {
1035
+ defaultAnalyzer = new TreeSitterAnalyzer();
1036
+ await defaultAnalyzer.initialize();
1037
+ }
1038
+ return defaultAnalyzer;
1039
+ }
1040
+ async function extractSymbols(filePaths, options) {
1041
+ const analyzer = await getAnalyzer();
1042
+ return analyzer.extractSymbols(filePaths, options);
1043
+ }
1044
+ async function getRepoMap(root, options) {
1045
+ const analyzer = await getAnalyzer();
1046
+ return analyzer.getRepoMap({ ...options, root });
1047
+ }
1048
+ // Annotate the CommonJS export names for ESM import in node:
1049
+ 0 && (module.exports = {
1050
+ CacheManager,
1051
+ GraphBuilder,
1052
+ PageRankCalculator,
1053
+ SymbolExtractor,
1054
+ TreeRenderer,
1055
+ TreeSitterAnalyzer,
1056
+ TreeSitterParser,
1057
+ detectLanguage,
1058
+ downloadWasmForLanguage,
1059
+ extractSymbols,
1060
+ getAllFiles,
1061
+ getLanguageWasmConfig,
1062
+ getLogger,
1063
+ getRepoMap,
1064
+ getSupportedExtensions,
1065
+ getSupportedLanguages,
1066
+ getSupportedLanguagesForWasm,
1067
+ isLanguageSupported,
1068
+ setLogger
1069
+ });
1070
+ //# sourceMappingURL=index.js.map