deep-slop 1.4.1

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.
@@ -0,0 +1,661 @@
1
+ import { createRequire } from "node:module";
2
+
3
+ //#region \0rolldown/runtime.js
4
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
5
+
6
+ //#endregion
7
+ //#region src/utils/tree-sitter.ts
8
+ let parserInstance = null;
9
+ let tsLang = null;
10
+ let tsxLang = null;
11
+ let initPromise = null;
12
+ let initDone = false;
13
+ let initOk = false;
14
+ let pyLang = null;
15
+ let pyInitDone = false;
16
+ let pyInitOk = false;
17
+ let goLang = null;
18
+ let goInitDone = false;
19
+ let goInitOk = false;
20
+ let rustLang = null;
21
+ let rustInitDone = false;
22
+ let rustInitOk = false;
23
+ let phpLang = null;
24
+ let phpInitDone = false;
25
+ let phpInitOk = false;
26
+ let csharpLang = null;
27
+ let csharpInitDone = false;
28
+ let csharpInitOk = false;
29
+ let swiftLang = null;
30
+ let swiftInitDone = false;
31
+ let swiftInitOk = false;
32
+ /**
33
+ * Attempt to initialise web-tree-sitter with the TypeScript grammar.
34
+ * Returns true on success; false on any failure (missing WASM, etc.).
35
+ * Safe to call multiple times – only the first call does real work.
36
+ */
37
+ async function initParser() {
38
+ if (initDone) return initOk;
39
+ if (initPromise) return initPromise;
40
+ initPromise = (async () => {
41
+ try {
42
+ const wt = await import("web-tree-sitter");
43
+ const { dirname } = await import("node:path");
44
+ const wasmDir = dirname(__require.resolve("web-tree-sitter/tree-sitter.wasm"));
45
+ await wt.Parser.init({ locateFile: (name) => `${wasmDir}/${name}` });
46
+ parserInstance = new wt.Parser();
47
+ const tsWasm = __require.resolve("tree-sitter-typescript/tree-sitter-typescript.wasm");
48
+ tsLang = await wt.Language.load(tsWasm);
49
+ const tsxWasm = __require.resolve("tree-sitter-typescript/tree-sitter-tsx.wasm");
50
+ tsxLang = await wt.Language.load(tsxWasm);
51
+ initDone = true;
52
+ initOk = true;
53
+ return true;
54
+ } catch (err) {
55
+ initDone = true;
56
+ initOk = false;
57
+ return false;
58
+ }
59
+ })();
60
+ return initPromise;
61
+ }
62
+ /**
63
+ * Attempt to load the Python grammar for tree-sitter.
64
+ * Returns true on success. Graceful fallback: returns false if
65
+ * tree-sitter-python is not installed.
66
+ */
67
+ async function initPythonParser() {
68
+ if (pyInitDone) return pyInitOk;
69
+ if (!initOk) {
70
+ if (!await initParser()) {
71
+ pyInitDone = true;
72
+ pyInitOk = false;
73
+ return false;
74
+ }
75
+ }
76
+ try {
77
+ const pyWasm = __require.resolve("tree-sitter-python/python.wasm");
78
+ pyLang = await (await import("web-tree-sitter")).Language.load(pyWasm);
79
+ pyInitDone = true;
80
+ pyInitOk = true;
81
+ return true;
82
+ } catch {
83
+ pyInitDone = true;
84
+ pyInitOk = false;
85
+ return false;
86
+ }
87
+ }
88
+ /**
89
+ * Attempt to load the Go grammar for tree-sitter.
90
+ * Returns true on success. Graceful fallback: returns false if
91
+ * tree-sitter-go is not installed.
92
+ */
93
+ async function initGoParser() {
94
+ if (goInitDone) return goInitOk;
95
+ if (!initOk) {
96
+ if (!await initParser()) {
97
+ goInitDone = true;
98
+ goInitOk = false;
99
+ return false;
100
+ }
101
+ }
102
+ try {
103
+ const goWasm = __require.resolve("tree-sitter-go/go.wasm");
104
+ goLang = await (await import("web-tree-sitter")).Language.load(goWasm);
105
+ goInitDone = true;
106
+ goInitOk = true;
107
+ return true;
108
+ } catch {
109
+ goInitDone = true;
110
+ goInitOk = false;
111
+ return false;
112
+ }
113
+ }
114
+ /**
115
+ * Attempt to load the Rust grammar for tree-sitter.
116
+ * Returns true on success. Graceful fallback: returns false if
117
+ * tree-sitter-rust is not installed.
118
+ */
119
+ async function initRustParser() {
120
+ if (rustInitDone) return rustInitOk;
121
+ if (!initOk) {
122
+ if (!await initParser()) {
123
+ rustInitDone = true;
124
+ rustInitOk = false;
125
+ return false;
126
+ }
127
+ }
128
+ try {
129
+ const rustWasm = __require.resolve("tree-sitter-rust/rust.wasm");
130
+ rustLang = await (await import("web-tree-sitter")).Language.load(rustWasm);
131
+ rustInitDone = true;
132
+ rustInitOk = true;
133
+ return true;
134
+ } catch {
135
+ rustInitDone = true;
136
+ rustInitOk = false;
137
+ return false;
138
+ }
139
+ }
140
+ /**
141
+ * Attempt to load the PHP grammar for tree-sitter.
142
+ * Returns true on success. Graceful fallback: returns false if
143
+ * tree-sitter-php is not installed.
144
+ */
145
+ async function initPhpParser() {
146
+ if (phpInitDone) return phpInitOk;
147
+ if (!initOk) {
148
+ if (!await initParser()) {
149
+ phpInitDone = true;
150
+ phpInitOk = false;
151
+ return false;
152
+ }
153
+ }
154
+ try {
155
+ const phpWasm = __require.resolve("tree-sitter-php/php.wasm");
156
+ phpLang = await (await import("web-tree-sitter")).Language.load(phpWasm);
157
+ phpInitDone = true;
158
+ phpInitOk = true;
159
+ return true;
160
+ } catch {
161
+ phpInitDone = true;
162
+ phpInitOk = false;
163
+ return false;
164
+ }
165
+ }
166
+ /**
167
+ * Attempt to load the C# grammar for tree-sitter.
168
+ * Returns true on success. Graceful fallback: returns false if
169
+ * tree-sitter-c-sharp is not installed.
170
+ */
171
+ async function initCsharpParser() {
172
+ if (csharpInitDone) return csharpInitOk;
173
+ if (!initOk) {
174
+ if (!await initParser()) {
175
+ csharpInitDone = true;
176
+ csharpInitOk = false;
177
+ return false;
178
+ }
179
+ }
180
+ try {
181
+ const csharpWasm = __require.resolve("tree-sitter-c-sharp/c_sharp.wasm");
182
+ csharpLang = await (await import("web-tree-sitter")).Language.load(csharpWasm);
183
+ csharpInitDone = true;
184
+ csharpInitOk = true;
185
+ return true;
186
+ } catch {
187
+ csharpInitDone = true;
188
+ csharpInitOk = false;
189
+ return false;
190
+ }
191
+ }
192
+ /**
193
+ * Attempt to load the Swift grammar for tree-sitter.
194
+ * Returns true on success. Graceful fallback: returns false if
195
+ * tree-sitter-swift is not installed.
196
+ */
197
+ async function initSwiftParser() {
198
+ if (swiftInitDone) return swiftInitOk;
199
+ if (!initOk) {
200
+ if (!await initParser()) {
201
+ swiftInitDone = true;
202
+ swiftInitOk = false;
203
+ return false;
204
+ }
205
+ }
206
+ try {
207
+ const swiftWasm = __require.resolve("tree-sitter-swift/swift.wasm");
208
+ swiftLang = await (await import("web-tree-sitter")).Language.load(swiftWasm);
209
+ swiftInitDone = true;
210
+ swiftInitOk = true;
211
+ return true;
212
+ } catch {
213
+ swiftInitDone = true;
214
+ swiftInitOk = false;
215
+ return false;
216
+ }
217
+ }
218
+ /** Check if tree-sitter is available and initialized */
219
+ function isAvailable() {
220
+ return initOk && parserInstance !== null;
221
+ }
222
+ /** Check if Python tree-sitter grammar is available */
223
+ function isPythonAvailable() {
224
+ return pyInitOk && pyLang !== null;
225
+ }
226
+ /**
227
+ * Parse a source file into an AST tree.
228
+ * Returns null if tree-sitter is not available or parsing fails.
229
+ *
230
+ * When `filePath` is provided, routes to the correct language parser
231
+ * based on file extension (.go, .rs, .php, .cs, .swift, .py, .tsx, .jsx).
232
+ * When omitted, parses as TypeScript (or TSX when `isTsx` is true).
233
+ */
234
+ async function parseFile(content, isTsx = false, filePath) {
235
+ if (filePath) {
236
+ const ext = filePath.toLowerCase();
237
+ if (ext.endsWith(".go")) return parseGoFile(content);
238
+ if (ext.endsWith(".rs")) return parseRustFile(content);
239
+ if (ext.endsWith(".php")) return parsePhpFile(content);
240
+ if (ext.endsWith(".cs")) return parseCsharpFile(content);
241
+ if (ext.endsWith(".swift")) return parseSwiftFile(content);
242
+ if (ext.endsWith(".py")) return parsePython(content);
243
+ }
244
+ if (!parserInstance || !tsLang && !tsxLang) {
245
+ if (!await initParser()) return null;
246
+ }
247
+ try {
248
+ const lang = isTsx ? tsxLang : tsLang;
249
+ parserInstance.setLanguage(lang);
250
+ const tree = parserInstance.parse(content);
251
+ if (!tree) return null;
252
+ return convertNode(tree.rootNode, null);
253
+ } catch {
254
+ return null;
255
+ }
256
+ }
257
+ /**
258
+ * Parse Python source content into an AST tree.
259
+ * Returns null if tree-sitter-python is not available or parsing fails.
260
+ */
261
+ async function parsePython(content) {
262
+ if (!pyLang) {
263
+ if (!await initPythonParser()) return null;
264
+ }
265
+ if (!parserInstance) {
266
+ if (!await initParser()) return null;
267
+ }
268
+ try {
269
+ parserInstance.setLanguage(pyLang);
270
+ const tree = parserInstance.parse(content);
271
+ if (!tree) return null;
272
+ return convertNode(tree.rootNode, null);
273
+ } catch {
274
+ return null;
275
+ }
276
+ }
277
+ /**
278
+ * Parse Go source content into an AST tree.
279
+ * Returns null if tree-sitter-go is not available or parsing fails.
280
+ */
281
+ async function parseGoFile(content) {
282
+ if (!goLang) {
283
+ if (!await initGoParser()) return null;
284
+ }
285
+ if (!parserInstance) {
286
+ if (!await initParser()) return null;
287
+ }
288
+ try {
289
+ parserInstance.setLanguage(goLang);
290
+ const tree = parserInstance.parse(content);
291
+ if (!tree) return null;
292
+ return convertNode(tree.rootNode, null);
293
+ } catch {
294
+ return null;
295
+ }
296
+ }
297
+ /**
298
+ * Parse Rust source content into an AST tree.
299
+ * Returns null if tree-sitter-rust is not available or parsing fails.
300
+ */
301
+ async function parseRustFile(content) {
302
+ if (!rustLang) {
303
+ if (!await initRustParser()) return null;
304
+ }
305
+ if (!parserInstance) {
306
+ if (!await initParser()) return null;
307
+ }
308
+ try {
309
+ parserInstance.setLanguage(rustLang);
310
+ const tree = parserInstance.parse(content);
311
+ if (!tree) return null;
312
+ return convertNode(tree.rootNode, null);
313
+ } catch {
314
+ return null;
315
+ }
316
+ }
317
+ /**
318
+ * Parse PHP source content into an AST tree.
319
+ * Returns null if tree-sitter-php is not available or parsing fails.
320
+ */
321
+ async function parsePhpFile(content) {
322
+ if (!phpLang) {
323
+ if (!await initPhpParser()) return null;
324
+ }
325
+ if (!parserInstance) {
326
+ if (!await initParser()) return null;
327
+ }
328
+ try {
329
+ parserInstance.setLanguage(phpLang);
330
+ const tree = parserInstance.parse(content);
331
+ if (!tree) return null;
332
+ return convertNode(tree.rootNode, null);
333
+ } catch {
334
+ return null;
335
+ }
336
+ }
337
+ /**
338
+ * Parse C# source content into an AST tree.
339
+ * Returns null if tree-sitter-c-sharp is not available or parsing fails.
340
+ */
341
+ async function parseCsharpFile(content) {
342
+ if (!csharpLang) {
343
+ if (!await initCsharpParser()) return null;
344
+ }
345
+ if (!parserInstance) {
346
+ if (!await initParser()) return null;
347
+ }
348
+ try {
349
+ parserInstance.setLanguage(csharpLang);
350
+ const tree = parserInstance.parse(content);
351
+ if (!tree) return null;
352
+ return convertNode(tree.rootNode, null);
353
+ } catch {
354
+ return null;
355
+ }
356
+ }
357
+ /**
358
+ * Parse Swift source content into an AST tree.
359
+ * Returns null if tree-sitter-swift is not available or parsing fails.
360
+ */
361
+ async function parseSwiftFile(content) {
362
+ if (!swiftLang) {
363
+ if (!await initSwiftParser()) return null;
364
+ }
365
+ if (!parserInstance) {
366
+ if (!await initParser()) return null;
367
+ }
368
+ try {
369
+ parserInstance.setLanguage(swiftLang);
370
+ const tree = parserInstance.parse(content);
371
+ if (!tree) return null;
372
+ return convertNode(tree.rootNode, null);
373
+ } catch {
374
+ return null;
375
+ }
376
+ }
377
+ /**
378
+ * Find all descendant nodes of a given type.
379
+ */
380
+ function findNodesOfType(root, type) {
381
+ const results = [];
382
+ function walk(node) {
383
+ if (node.type === type) results.push(node);
384
+ for (const child of node.children) walk(child);
385
+ }
386
+ walk(root);
387
+ return results;
388
+ }
389
+ /**
390
+ * Find all descendant nodes matching any of the given types.
391
+ */
392
+ function findNodesOfTypes(root, types) {
393
+ const typeSet = new Set(types);
394
+ const results = [];
395
+ function walk(node) {
396
+ if (typeSet.has(node.type)) results.push(node);
397
+ for (const child of node.children) walk(child);
398
+ }
399
+ walk(root);
400
+ return results;
401
+ }
402
+ /**
403
+ * Walk the AST depth-first, calling visitor on each node.
404
+ * Return false from visitor to skip children.
405
+ */
406
+ function walkAST(root, visitor) {
407
+ function walk(node) {
408
+ if (visitor(node) !== false) for (const child of node.children) walk(child);
409
+ }
410
+ walk(root);
411
+ }
412
+ /**
413
+ * Find the nearest ancestor of a node matching a type predicate.
414
+ */
415
+ function findAncestor(node, predicate) {
416
+ let current = node.parent;
417
+ while (current) {
418
+ if (predicate(current)) return current;
419
+ current = current.parent;
420
+ }
421
+ return null;
422
+ }
423
+ /**
424
+ * Check if a node is inside a try/catch block.
425
+ */
426
+ function isInsideCatch(node) {
427
+ return findAncestor(node, (n) => n.type === "catch_clause") !== null;
428
+ }
429
+ /** Find ancestor of specific type */
430
+ function findAncestorOfType(node, type) {
431
+ return findAncestor(node, (n) => n.type === type);
432
+ }
433
+ /** Check if a catch clause body is empty (only contains comments or whitespace) */
434
+ function isCatchBodyEmpty(catchNode) {
435
+ if (catchNode.type !== "catch_clause") return false;
436
+ const body = catchNode.children.find((c) => c.type === "statement_block" || c.type === "block");
437
+ if (!body) return true;
438
+ return body.children.filter((c) => c.type !== "comment" && c.type !== "//" && c.type !== "/*" && c.type !== "{" && c.type !== "}" && c.text.trim() !== "").length === 0;
439
+ }
440
+ /** Get the type annotation from an `as` expression (e.g., `x as any` → "any") */
441
+ function getAsExpressionType(node) {
442
+ if (node.type !== "as_expression") return null;
443
+ return node.children.find((c) => c.fieldName === "type")?.text ?? null;
444
+ }
445
+ /** Get context of an `as` expression — returns 'catch', 'orm', 'json', 'variable', or 'unknown' */
446
+ function getAsExpressionContext(node) {
447
+ if (isInsideCatch(node)) return "catch";
448
+ const funcAncestor = findAncestor(node, (n) => [
449
+ "function_declaration",
450
+ "arrow_function",
451
+ "method_definition"
452
+ ].includes(n.type));
453
+ if (funcAncestor) {
454
+ const text = funcAncestor.text.toLowerCase();
455
+ if (/prisma|drizzle|sequelize|mongoose|typeorm|knex|supabase/.test(text)) return "orm";
456
+ if (/json\.parse|parse\(/.test(text)) return "json";
457
+ }
458
+ return "unknown";
459
+ }
460
+ /** Extract import info from an import_statement or import_declaration node */
461
+ function extractImportFromNode(node) {
462
+ if (node.type !== "import_statement" && node.type !== "import_declaration") return null;
463
+ const sourceNode = node.children.find((c) => c.type === "string" || c.fieldName === "source");
464
+ if (!sourceNode) return null;
465
+ const source = sourceNode.text.replace(/^['"]|['"]$/g, "");
466
+ const isTypeOnly = node.text.includes("import type ");
467
+ const symbols = [];
468
+ const namedImport = node.children.find((c) => c.type === "named_imports" || c.type === "import_clause");
469
+ if (namedImport) {
470
+ for (const child of namedImport.children) if (child.type === "identifier" || child.type === "type_identifier" || child.type === "import_specifier") symbols.push(child.text);
471
+ }
472
+ return {
473
+ source,
474
+ symbols,
475
+ line: node.startRow + 1,
476
+ isTypeOnly
477
+ };
478
+ }
479
+ /**
480
+ * Find all Python function definitions in an AST.
481
+ */
482
+ function findPythonFunctions(root) {
483
+ const funcNodes = findNodesOfTypes(root, ["function_definition", "decorated_definition"]);
484
+ const results = [];
485
+ for (const node of funcNodes) if (node.type === "decorated_definition") {
486
+ const inner = node.children.find((c) => c.type === "function_definition");
487
+ if (inner) results.push(extractPythonFunctionInfo(inner, node));
488
+ } else results.push(extractPythonFunctionInfo(node));
489
+ return results;
490
+ }
491
+ /**
492
+ * Find all Python class definitions in an AST.
493
+ */
494
+ function findPythonClasses(root) {
495
+ const classNodes = findNodesOfTypes(root, ["class_definition", "decorated_definition"]);
496
+ const results = [];
497
+ for (const node of classNodes) if (node.type === "decorated_definition") {
498
+ const inner = node.children.find((c) => c.type === "class_definition");
499
+ if (inner) results.push(extractPythonClassInfo(inner, node));
500
+ } else results.push(extractPythonClassInfo(node));
501
+ return results;
502
+ }
503
+ /**
504
+ * Find all Python import statements in an AST.
505
+ */
506
+ function findPythonImports(root) {
507
+ return findNodesOfTypes(root, ["import_statement", "import_from_statement"]).map(extractPythonImportInfo);
508
+ }
509
+ /**
510
+ * Check if a Python function body is essentially empty
511
+ * (only contains pass, ..., or docstrings).
512
+ */
513
+ function isPythonFunctionStub(funcInfo) {
514
+ const bodyLines = funcInfo.text.split("\n").slice(1).join("\n").trim();
515
+ if (/^(\s*(pass|\.\.\.)\s*)$/.test(bodyLines)) return true;
516
+ const docstringOnly = bodyLines.replace(/"""[\s\S]*?"""/g, "").replace(/'''[\s\S]*?'''/g, "").trim();
517
+ if (docstringOnly === "" || docstringOnly === "pass" || docstringOnly === "...") return true;
518
+ return false;
519
+ }
520
+ /**
521
+ * Detect Python AI patterns in an AST.
522
+ * Returns diagnostic-like findings for the ast-slop engine.
523
+ */
524
+ function detectPythonAIPatterns(root) {
525
+ const findings = [];
526
+ const functions = findPythonFunctions(root);
527
+ for (const fn of functions) if (isPythonFunctionStub(fn)) findings.push({
528
+ type: "python-stub-function",
529
+ message: `Function '${fn.name}' is a stub (only pass/ellipsis)`,
530
+ line: fn.line
531
+ });
532
+ const tryNodes = findNodesOfType(root, "try_statement");
533
+ for (const tryNode of tryNodes) {
534
+ const exceptNodes = tryNode.children.filter((c) => c.type === "except_clause");
535
+ for (const exceptNode of exceptNodes) if (!exceptNode.children.some((c) => c.type === "identifier" || c.type === "tuple")) {
536
+ exceptNode.children.find((c) => c.text && c.text.includes("except"));
537
+ findings.push({
538
+ type: "python-bare-except",
539
+ message: "Bare except clause catches all exceptions",
540
+ line: exceptNode.startRow + 1
541
+ });
542
+ }
543
+ }
544
+ const commentNodes = findNodesOfType(root, "comment");
545
+ for (const comment of commentNodes) {
546
+ const text = comment.text.toLowerCase();
547
+ if (/todo|fixme|hack|xxx/.test(text)) findings.push({
548
+ type: "python-todo-stub",
549
+ message: `TODO/FIXME comment: ${comment.text.trim()}`,
550
+ line: comment.startRow + 1
551
+ });
552
+ }
553
+ const callNodes = findNodesOfType(root, "call");
554
+ for (const call of callNodes) {
555
+ const func = call.children[0];
556
+ if (func && func.text === "print") findings.push({
557
+ type: "python-print-leftover",
558
+ message: "print() statement — likely debug leftover",
559
+ line: call.startRow + 1
560
+ });
561
+ }
562
+ return findings;
563
+ }
564
+ function extractPythonFunctionInfo(funcNode, decoratedParent) {
565
+ const name = (funcNode.children.find((c) => c.fieldName === "name") ?? funcNode.children.find((c) => c.type === "identifier"))?.text ?? "(anonymous)";
566
+ const params = funcNode.children.find((c) => c.type === "parameters");
567
+ const parameters = params ? params.children.filter((c) => c.type === "identifier" || c.type === "typed_parameter" || c.type === "default_parameter").map((c) => c.children[0]?.text ?? c.text) : [];
568
+ const isAsync = funcNode.children.some((c) => c.type === "async");
569
+ const decorators = [];
570
+ if (decoratedParent) {
571
+ for (const child of decoratedParent.children) if (child.type === "decorator") decorators.push(child.text.replace("@", ""));
572
+ }
573
+ return {
574
+ name,
575
+ decorators,
576
+ parameters,
577
+ isAsync,
578
+ line: funcNode.startRow + 1,
579
+ endLine: funcNode.endRow + 1,
580
+ text: funcNode.text
581
+ };
582
+ }
583
+ function extractPythonClassInfo(classNode, decoratedParent) {
584
+ const name = (classNode.children.find((c) => c.fieldName === "name") ?? classNode.children.find((c) => c.type === "identifier"))?.text ?? "(anonymous)";
585
+ const argList = classNode.children.find((c) => c.type === "argument_list");
586
+ const bases = argList ? argList.children.filter((c) => c.type === "identifier" || c.type === "attribute").map((c) => c.text) : [];
587
+ const decorators = [];
588
+ if (decoratedParent) {
589
+ for (const child of decoratedParent.children) if (child.type === "decorator") decorators.push(child.text.replace("@", ""));
590
+ }
591
+ const body = classNode.children.find((c) => c.type === "block");
592
+ const methods = [];
593
+ if (body) {
594
+ for (const child of body.children) if (child.type === "function_definition") methods.push(extractPythonFunctionInfo(child));
595
+ else if (child.type === "decorated_definition") {
596
+ const inner = child.children.find((c) => c.type === "function_definition");
597
+ if (inner) methods.push(extractPythonFunctionInfo(inner, child));
598
+ }
599
+ }
600
+ return {
601
+ name,
602
+ bases,
603
+ decorators,
604
+ methods,
605
+ line: classNode.startRow + 1,
606
+ endLine: classNode.endRow + 1,
607
+ text: classNode.text
608
+ };
609
+ }
610
+ function extractPythonImportInfo(importNode) {
611
+ const isFromImport = importNode.type === "import_from_statement";
612
+ let module = "";
613
+ const symbols = [];
614
+ if (isFromImport) {
615
+ const moduleNode = importNode.children.find((c) => c.fieldName === "module_name" || c.type === "dotted_name" && c.fieldName !== "name" || c.type === "identifier" && c.fieldName !== "name");
616
+ module = moduleNode?.text ?? "";
617
+ const nameList = importNode.children.find((c) => c.type === "dotted_name" && c !== moduleNode);
618
+ const identifierChildren = importNode.children.filter((c) => c.type === "identifier" && c !== moduleNode);
619
+ if (nameList) symbols.push(nameList.text);
620
+ for (const id of identifierChildren) if (id.text !== "from" && id.text !== "import" && id.text !== module) symbols.push(id.text);
621
+ } else {
622
+ const dottedNames = importNode.children.filter((c) => c.type === "dotted_name");
623
+ const identifiers = importNode.children.filter((c) => c.type === "identifier");
624
+ for (const dn of dottedNames) symbols.push(dn.text);
625
+ for (const id of identifiers) if (id.text !== "import") symbols.push(id.text);
626
+ module = symbols[0] ?? "";
627
+ }
628
+ return {
629
+ module,
630
+ symbols,
631
+ isFromImport,
632
+ line: importNode.startRow + 1,
633
+ text: importNode.text
634
+ };
635
+ }
636
+ function convertNode(node, parent) {
637
+ const children = [];
638
+ const astNode = {
639
+ type: node.type,
640
+ text: node.text,
641
+ startRow: node.startPosition.row,
642
+ startCol: node.startPosition.column,
643
+ endRow: node.endPosition.row,
644
+ endCol: node.endPosition.column,
645
+ children,
646
+ parent,
647
+ fieldName: null
648
+ };
649
+ for (let i = 0; i < node.childCount; i++) {
650
+ const child = node.child(i);
651
+ if (child) {
652
+ const converted = convertNode(child, astNode);
653
+ converted.fieldName = node.fieldNameForChild(i) ?? null;
654
+ children.push(converted);
655
+ }
656
+ }
657
+ return astNode;
658
+ }
659
+
660
+ //#endregion
661
+ export { parseFile as _, findNodesOfType as a, findPythonImports as c, initParser as d, initPythonParser as f, isPythonAvailable as g, isInsideCatch as h, findAncestorOfType as i, getAsExpressionContext as l, isCatchBodyEmpty as m, extractImportFromNode as n, findNodesOfTypes as o, isAvailable as p, findAncestor as r, findPythonClasses as s, detectPythonAIPatterns as t, getAsExpressionType as u, parsePython as v, walkAST as y };