universal-ast-mapper 1.27.0 → 2.0.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.
- package/BLUEPRINT.md +230 -230
- package/CHANGELOG.md +466 -321
- package/README.md +878 -877
- package/package.json +48 -47
- package/scripts/install-skill.mjs +187 -187
- package/dist/analysis.js +0 -134
- package/dist/callgraph.js +0 -467
- package/dist/check.js +0 -112
- package/dist/cli.js +0 -1275
- package/dist/complexity.js +0 -98
- package/dist/config.js +0 -53
- package/dist/contextpack.js +0 -79
- package/dist/coupling.js +0 -35
- package/dist/crosslang.js +0 -425
- package/dist/diskcache.js +0 -97
- package/dist/explorer.js +0 -123
- package/dist/extractors/c.js +0 -204
- package/dist/extractors/common.js +0 -56
- package/dist/extractors/cpp.js +0 -272
- package/dist/extractors/csharp.js +0 -209
- package/dist/extractors/go.js +0 -212
- package/dist/extractors/java.js +0 -152
- package/dist/extractors/kotlin.js +0 -159
- package/dist/extractors/php.js +0 -208
- package/dist/extractors/python.js +0 -153
- package/dist/extractors/ruby.js +0 -146
- package/dist/extractors/rust.js +0 -249
- package/dist/extractors/swift.js +0 -192
- package/dist/extractors/typescript.js +0 -577
- package/dist/gitdiff.js +0 -178
- package/dist/graph-analysis.js +0 -279
- package/dist/graph.js +0 -165
- package/dist/html.js +0 -326
- package/dist/index.js +0 -1407
- package/dist/layers.js +0 -36
- package/dist/modulecoupling.js +0 -0
- package/dist/parser.js +0 -84
- package/dist/pool.js +0 -114
- package/dist/prompts.js +0 -67
- package/dist/registry.js +0 -87
- package/dist/report.js +0 -187
- package/dist/resolver.js +0 -222
- package/dist/roots.js +0 -47
- package/dist/search.js +0 -68
- package/dist/semantic.js +0 -365
- package/dist/sfc.js +0 -27
- package/dist/skeleton.js +0 -132
- package/dist/sourcemap.js +0 -60
- package/dist/testmap.js +0 -167
- package/dist/tsconfig.js +0 -212
- package/dist/typeflow.js +0 -124
- package/dist/types.js +0 -5
- package/dist/unused-params.js +0 -127
- package/dist/worker.js +0 -27
- package/dist/workspace.js +0 -330
package/dist/extractors/java.js
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import { namedChildren, nameOf, headerSignature, leadingComment } from "../parser.js";
|
|
2
|
-
import { makeSymbol } from "./common.js";
|
|
3
|
-
/* ─── helpers ─────────────────────────────────────────────────────────────── */
|
|
4
|
-
function childOfType(node, type) {
|
|
5
|
-
for (let i = 0; i < node.childCount; i++) {
|
|
6
|
-
const c = node.child(i);
|
|
7
|
-
if (c && c.type === type)
|
|
8
|
-
return c;
|
|
9
|
-
}
|
|
10
|
-
return null;
|
|
11
|
-
}
|
|
12
|
-
function modifiersText(node) {
|
|
13
|
-
const m = childOfType(node, "modifiers");
|
|
14
|
-
return m ? m.text : "";
|
|
15
|
-
}
|
|
16
|
-
function vis(node) {
|
|
17
|
-
const m = modifiersText(node);
|
|
18
|
-
if (/\b(private|protected)\b/.test(m))
|
|
19
|
-
return "private";
|
|
20
|
-
return "public";
|
|
21
|
-
}
|
|
22
|
-
function exported(node) {
|
|
23
|
-
return /\bpublic\b/.test(modifiersText(node));
|
|
24
|
-
}
|
|
25
|
-
/* ─── directives (package declaration) ────────────────────────────────────── */
|
|
26
|
-
export function extractDirectivesJava(root, _source) {
|
|
27
|
-
for (const child of namedChildren(root)) {
|
|
28
|
-
if (child.type !== "package_declaration")
|
|
29
|
-
continue;
|
|
30
|
-
const id = childOfType(child, "scoped_identifier") ?? childOfType(child, "identifier");
|
|
31
|
-
if (id)
|
|
32
|
-
return [`package:${id.text}`];
|
|
33
|
-
}
|
|
34
|
-
return [];
|
|
35
|
-
}
|
|
36
|
-
/* ─── import extraction ───────────────────────────────────────────────────── */
|
|
37
|
-
export function extractImportsJava(root, _source) {
|
|
38
|
-
const out = [];
|
|
39
|
-
for (const child of namedChildren(root)) {
|
|
40
|
-
if (child.type !== "import_declaration")
|
|
41
|
-
continue;
|
|
42
|
-
const isStatic = /\bstatic\b/.test(child.text);
|
|
43
|
-
const isWildcard = /\.\s*\*/.test(child.text);
|
|
44
|
-
const pathNode = childOfType(child, "scoped_identifier") ?? childOfType(child, "identifier");
|
|
45
|
-
const from = pathNode ? pathNode.text : child.text.replace(/^import\s+|;\s*$/g, "").trim();
|
|
46
|
-
if (isWildcard) {
|
|
47
|
-
out.push({ symbol: "*", from, isNamespaceImport: true, isTypeOnly: !isStatic });
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
const symbol = from.split(".").pop() ?? from;
|
|
51
|
-
out.push({ symbol, from, isTypeOnly: !isStatic });
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return out;
|
|
55
|
-
}
|
|
56
|
-
/* ─── symbol extraction ───────────────────────────────────────────────────── */
|
|
57
|
-
export function extractJava(root, _source) {
|
|
58
|
-
return collect(namedChildren(root));
|
|
59
|
-
}
|
|
60
|
-
function collect(nodes) {
|
|
61
|
-
const out = [];
|
|
62
|
-
for (const n of nodes) {
|
|
63
|
-
const res = handle(n);
|
|
64
|
-
if (Array.isArray(res))
|
|
65
|
-
out.push(...res);
|
|
66
|
-
else if (res)
|
|
67
|
-
out.push(res);
|
|
68
|
-
}
|
|
69
|
-
return out;
|
|
70
|
-
}
|
|
71
|
-
function handle(node) {
|
|
72
|
-
switch (node.type) {
|
|
73
|
-
case "class_declaration":
|
|
74
|
-
case "record_declaration": {
|
|
75
|
-
const body = node.childForFieldName("body");
|
|
76
|
-
return makeSymbol({
|
|
77
|
-
name: nameOf(node) ?? "(class)",
|
|
78
|
-
kind: "class",
|
|
79
|
-
node,
|
|
80
|
-
rawKind: node.type,
|
|
81
|
-
visibility: vis(node),
|
|
82
|
-
exported: exported(node),
|
|
83
|
-
doc: leadingComment(node),
|
|
84
|
-
children: body ? collect(namedChildren(body)) : [],
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
case "interface_declaration": {
|
|
88
|
-
const body = node.childForFieldName("body");
|
|
89
|
-
return makeSymbol({
|
|
90
|
-
name: nameOf(node) ?? "(interface)",
|
|
91
|
-
kind: "interface",
|
|
92
|
-
node,
|
|
93
|
-
rawKind: node.type,
|
|
94
|
-
visibility: vis(node),
|
|
95
|
-
exported: exported(node),
|
|
96
|
-
doc: leadingComment(node),
|
|
97
|
-
children: body ? collect(namedChildren(body)) : [],
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
case "enum_declaration": {
|
|
101
|
-
const body = node.childForFieldName("body");
|
|
102
|
-
return makeSymbol({
|
|
103
|
-
name: nameOf(node) ?? "(enum)",
|
|
104
|
-
kind: "enum",
|
|
105
|
-
node,
|
|
106
|
-
rawKind: node.type,
|
|
107
|
-
visibility: vis(node),
|
|
108
|
-
exported: exported(node),
|
|
109
|
-
doc: leadingComment(node),
|
|
110
|
-
children: body ? collect(namedChildren(body).filter((c) => c.type !== "enum_constant")) : [],
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
case "method_declaration":
|
|
114
|
-
case "constructor_declaration":
|
|
115
|
-
return makeSymbol({
|
|
116
|
-
name: nameOf(node) ?? "(method)",
|
|
117
|
-
kind: "method",
|
|
118
|
-
node,
|
|
119
|
-
rawKind: node.type,
|
|
120
|
-
signature: headerSignature(node, node.childForFieldName("body")),
|
|
121
|
-
visibility: vis(node),
|
|
122
|
-
exported: exported(node),
|
|
123
|
-
doc: leadingComment(node),
|
|
124
|
-
});
|
|
125
|
-
case "field_declaration":
|
|
126
|
-
return fieldDeclarators(node);
|
|
127
|
-
default:
|
|
128
|
-
return null;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
function fieldDeclarators(node) {
|
|
132
|
-
const m = modifiersText(node);
|
|
133
|
-
const kind = /\bstatic\b/.test(m) && /\bfinal\b/.test(m) ? "const" : "field";
|
|
134
|
-
const out = [];
|
|
135
|
-
for (const decl of namedChildren(node)) {
|
|
136
|
-
if (decl.type !== "variable_declarator")
|
|
137
|
-
continue;
|
|
138
|
-
const name = nameOf(decl);
|
|
139
|
-
if (!name)
|
|
140
|
-
continue;
|
|
141
|
-
out.push(makeSymbol({
|
|
142
|
-
name,
|
|
143
|
-
kind,
|
|
144
|
-
node: decl,
|
|
145
|
-
rawKind: node.type,
|
|
146
|
-
signature: node.text.replace(/\s+/g, " ").replace(/;$/, "").trim(),
|
|
147
|
-
visibility: vis(node),
|
|
148
|
-
exported: exported(node),
|
|
149
|
-
}));
|
|
150
|
-
}
|
|
151
|
-
return out;
|
|
152
|
-
}
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import { namedChildren, headerSignature, leadingComment } from "../parser.js";
|
|
2
|
-
import { makeSymbol } from "./common.js";
|
|
3
|
-
/* ─── helpers ─────────────────────────────────────────────────────────────── */
|
|
4
|
-
function childOfType(node, type) {
|
|
5
|
-
for (let i = 0; i < node.childCount; i++) {
|
|
6
|
-
const c = node.child(i);
|
|
7
|
-
if (c && c.type === type)
|
|
8
|
-
return c;
|
|
9
|
-
}
|
|
10
|
-
return null;
|
|
11
|
-
}
|
|
12
|
-
function firstChildOfTypes(node, types) {
|
|
13
|
-
for (let i = 0; i < node.namedChildCount; i++) {
|
|
14
|
-
const c = node.namedChild(i);
|
|
15
|
-
if (c && types.has(c.type))
|
|
16
|
-
return c;
|
|
17
|
-
}
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
const TYPE_NAME_NODES = new Set(["type_identifier", "simple_identifier"]);
|
|
21
|
-
const SIMPLE_NAME_NODES = new Set(["simple_identifier"]);
|
|
22
|
-
function modifiersText(node) {
|
|
23
|
-
const m = childOfType(node, "modifiers");
|
|
24
|
-
return m ? m.text : "";
|
|
25
|
-
}
|
|
26
|
-
function vis(node) {
|
|
27
|
-
const m = modifiersText(node);
|
|
28
|
-
if (/\b(private|protected|internal)\b/.test(m))
|
|
29
|
-
return "private";
|
|
30
|
-
return "public"; // Kotlin default is public
|
|
31
|
-
}
|
|
32
|
-
function exported(node) {
|
|
33
|
-
const m = modifiersText(node);
|
|
34
|
-
if (/\b(private|protected|internal)\b/.test(m))
|
|
35
|
-
return false;
|
|
36
|
-
return true;
|
|
37
|
-
}
|
|
38
|
-
function classKind(node) {
|
|
39
|
-
const m = modifiersText(node);
|
|
40
|
-
if (/\bdata\b/.test(node.text.slice(0, 80)))
|
|
41
|
-
return "class";
|
|
42
|
-
if (/\benum\b/.test(node.text.slice(0, 80)))
|
|
43
|
-
return "enum";
|
|
44
|
-
return "class";
|
|
45
|
-
}
|
|
46
|
-
/* ─── imports + package ───────────────────────────────────────────────────── */
|
|
47
|
-
export function extractDirectivesKotlin(root, _source) {
|
|
48
|
-
for (const c of namedChildren(root)) {
|
|
49
|
-
if (c.type === "package_header") {
|
|
50
|
-
const id = childOfType(c, "identifier");
|
|
51
|
-
if (id)
|
|
52
|
-
return [`package:${id.text}`];
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return [];
|
|
56
|
-
}
|
|
57
|
-
export function extractImportsKotlin(root, _source) {
|
|
58
|
-
const out = [];
|
|
59
|
-
const list = childOfType(root, "import_list");
|
|
60
|
-
if (!list)
|
|
61
|
-
return out;
|
|
62
|
-
for (const h of namedChildren(list)) {
|
|
63
|
-
if (h.type !== "import_header")
|
|
64
|
-
continue;
|
|
65
|
-
const id = childOfType(h, "identifier");
|
|
66
|
-
if (!id)
|
|
67
|
-
continue;
|
|
68
|
-
const isWildcard = /\.\*\s*$/.test(h.text);
|
|
69
|
-
const from = id.text;
|
|
70
|
-
const sym = isWildcard ? "*" : (from.split(".").pop() ?? from);
|
|
71
|
-
out.push({ symbol: sym, from, isNamespaceImport: isWildcard });
|
|
72
|
-
}
|
|
73
|
-
return out;
|
|
74
|
-
}
|
|
75
|
-
/* ─── symbol extraction ───────────────────────────────────────────────────── */
|
|
76
|
-
export function extractKotlin(root, _source) {
|
|
77
|
-
return collect(namedChildren(root), false);
|
|
78
|
-
}
|
|
79
|
-
function collect(nodes, insideClass) {
|
|
80
|
-
const out = [];
|
|
81
|
-
for (const n of nodes) {
|
|
82
|
-
const res = handle(n, insideClass);
|
|
83
|
-
if (res)
|
|
84
|
-
out.push(res);
|
|
85
|
-
}
|
|
86
|
-
return out;
|
|
87
|
-
}
|
|
88
|
-
function handle(node, insideClass) {
|
|
89
|
-
switch (node.type) {
|
|
90
|
-
case "class_declaration": {
|
|
91
|
-
const nameNode = firstChildOfTypes(node, TYPE_NAME_NODES);
|
|
92
|
-
if (!nameNode)
|
|
93
|
-
return null;
|
|
94
|
-
const body = childOfType(node, "class_body") ?? childOfType(node, "enum_class_body");
|
|
95
|
-
return makeSymbol({
|
|
96
|
-
name: nameNode.text,
|
|
97
|
-
kind: classKind(node),
|
|
98
|
-
node,
|
|
99
|
-
rawKind: node.type,
|
|
100
|
-
visibility: vis(node),
|
|
101
|
-
exported: exported(node),
|
|
102
|
-
doc: leadingComment(node),
|
|
103
|
-
children: body ? collect(namedChildren(body), true) : [],
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
case "object_declaration": {
|
|
107
|
-
const nameNode = firstChildOfTypes(node, TYPE_NAME_NODES);
|
|
108
|
-
if (!nameNode)
|
|
109
|
-
return null;
|
|
110
|
-
const body = childOfType(node, "class_body");
|
|
111
|
-
return makeSymbol({
|
|
112
|
-
name: nameNode.text,
|
|
113
|
-
kind: "class",
|
|
114
|
-
node,
|
|
115
|
-
rawKind: node.type,
|
|
116
|
-
visibility: vis(node),
|
|
117
|
-
exported: exported(node),
|
|
118
|
-
doc: leadingComment(node),
|
|
119
|
-
children: body ? collect(namedChildren(body), true) : [],
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
case "function_declaration": {
|
|
123
|
-
const nameNode = firstChildOfTypes(node, SIMPLE_NAME_NODES);
|
|
124
|
-
if (!nameNode)
|
|
125
|
-
return null;
|
|
126
|
-
const body = childOfType(node, "function_body");
|
|
127
|
-
return makeSymbol({
|
|
128
|
-
name: nameNode.text,
|
|
129
|
-
kind: insideClass ? "method" : "function",
|
|
130
|
-
node,
|
|
131
|
-
rawKind: node.type,
|
|
132
|
-
signature: headerSignature(node, body),
|
|
133
|
-
visibility: vis(node),
|
|
134
|
-
exported: exported(node),
|
|
135
|
-
doc: leadingComment(node),
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
case "property_declaration": {
|
|
139
|
-
// variable_declaration → simple_identifier
|
|
140
|
-
const vd = childOfType(node, "variable_declaration");
|
|
141
|
-
const nameNode = vd ? firstChildOfTypes(vd, SIMPLE_NAME_NODES) : firstChildOfTypes(node, SIMPLE_NAME_NODES);
|
|
142
|
-
if (!nameNode)
|
|
143
|
-
return null;
|
|
144
|
-
const m = modifiersText(node);
|
|
145
|
-
const kind = insideClass ? "field" : (/\bconst\b/.test(m) ? "const" : "var");
|
|
146
|
-
return makeSymbol({
|
|
147
|
-
name: nameNode.text,
|
|
148
|
-
kind,
|
|
149
|
-
node,
|
|
150
|
-
rawKind: node.type,
|
|
151
|
-
signature: node.text.replace(/\s+/g, " ").trim(),
|
|
152
|
-
visibility: vis(node),
|
|
153
|
-
exported: exported(node),
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
default:
|
|
157
|
-
return null;
|
|
158
|
-
}
|
|
159
|
-
}
|
package/dist/extractors/php.js
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
import { namedChildren, nameOf, headerSignature, leadingComment } from "../parser.js";
|
|
2
|
-
import { makeSymbol } from "./common.js";
|
|
3
|
-
// ─── PHP extractor (tree-sitter-php) ──────────────────────────────────────────
|
|
4
|
-
export function extractPhp(root, _source) {
|
|
5
|
-
return collect(namedChildren(root));
|
|
6
|
-
}
|
|
7
|
-
function collect(nodes) {
|
|
8
|
-
const out = [];
|
|
9
|
-
for (const n of nodes) {
|
|
10
|
-
const sym = handle(n);
|
|
11
|
-
if (sym)
|
|
12
|
-
out.push(sym);
|
|
13
|
-
else if (n.type === "namespace_definition") {
|
|
14
|
-
// `namespace Foo;` (no braces) — siblings follow; emit the namespace marker.
|
|
15
|
-
const name = nameOf(n)?.replace(/\s+/g, "") ?? namespaceName(n);
|
|
16
|
-
if (name) {
|
|
17
|
-
out.push(makeSymbol({ name, kind: "namespace", node: n, rawKind: n.type }));
|
|
18
|
-
}
|
|
19
|
-
const body = n.childForFieldName("body");
|
|
20
|
-
if (body)
|
|
21
|
-
out[out.length - 1].children = collect(namedChildren(body));
|
|
22
|
-
}
|
|
23
|
-
else if (n.type === "expression_statement" || n.type === "if_statement") {
|
|
24
|
-
// skip — top-level statements
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return out;
|
|
28
|
-
}
|
|
29
|
-
function namespaceName(n) {
|
|
30
|
-
for (const c of namedChildren(n)) {
|
|
31
|
-
if (c.type === "namespace_name")
|
|
32
|
-
return c.text.replace(/\s+/g, "");
|
|
33
|
-
}
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
function phpVisibility(node) {
|
|
37
|
-
for (const c of namedChildren(node)) {
|
|
38
|
-
if (c.type === "visibility_modifier") {
|
|
39
|
-
const t = c.text;
|
|
40
|
-
if (t === "private" || t === "protected")
|
|
41
|
-
return "private";
|
|
42
|
-
return "public";
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
return "public";
|
|
46
|
-
}
|
|
47
|
-
function classLike(node, kind) {
|
|
48
|
-
const name = nameOf(node) ?? "(class)";
|
|
49
|
-
const body = node.childForFieldName("body") ?? findChild(node, "declaration_list");
|
|
50
|
-
return makeSymbol({
|
|
51
|
-
name,
|
|
52
|
-
kind,
|
|
53
|
-
node,
|
|
54
|
-
rawKind: node.type,
|
|
55
|
-
signature: headerSignature(node, body),
|
|
56
|
-
doc: leadingComment(node),
|
|
57
|
-
children: body ? collect(namedChildren(body)) : [],
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
function findChild(node, type) {
|
|
61
|
-
for (const c of namedChildren(node))
|
|
62
|
-
if (c.type === type)
|
|
63
|
-
return c;
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
function handle(node) {
|
|
67
|
-
switch (node.type) {
|
|
68
|
-
case "class_declaration":
|
|
69
|
-
case "trait_declaration":
|
|
70
|
-
return classLike(node, "class");
|
|
71
|
-
case "interface_declaration":
|
|
72
|
-
return classLike(node, "interface");
|
|
73
|
-
case "enum_declaration": {
|
|
74
|
-
const body = findChild(node, "enum_declaration_list");
|
|
75
|
-
return makeSymbol({
|
|
76
|
-
name: nameOf(node) ?? "(enum)",
|
|
77
|
-
kind: "enum",
|
|
78
|
-
node,
|
|
79
|
-
rawKind: node.type,
|
|
80
|
-
signature: headerSignature(node, body),
|
|
81
|
-
doc: leadingComment(node),
|
|
82
|
-
children: body
|
|
83
|
-
? namedChildren(body)
|
|
84
|
-
.filter((c) => c.type === "enum_case")
|
|
85
|
-
.map((c) => makeSymbol({ name: nameOf(c) ?? c.text, kind: "const", node: c, rawKind: c.type }))
|
|
86
|
-
: [],
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
case "function_definition": {
|
|
90
|
-
const body = node.childForFieldName("body") ?? findChild(node, "compound_statement");
|
|
91
|
-
return makeSymbol({
|
|
92
|
-
name: nameOf(node) ?? "(function)",
|
|
93
|
-
kind: "function",
|
|
94
|
-
node,
|
|
95
|
-
rawKind: node.type,
|
|
96
|
-
signature: headerSignature(node, body),
|
|
97
|
-
doc: leadingComment(node),
|
|
98
|
-
});
|
|
99
|
-
}
|
|
100
|
-
case "method_declaration": {
|
|
101
|
-
const body = node.childForFieldName("body") ?? findChild(node, "compound_statement");
|
|
102
|
-
const vis = phpVisibility(node);
|
|
103
|
-
return makeSymbol({
|
|
104
|
-
name: nameOf(node) ?? "(method)",
|
|
105
|
-
kind: "method",
|
|
106
|
-
node,
|
|
107
|
-
rawKind: node.type,
|
|
108
|
-
signature: headerSignature(node, body),
|
|
109
|
-
visibility: vis,
|
|
110
|
-
exported: vis === "public",
|
|
111
|
-
doc: leadingComment(node),
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
case "const_declaration": {
|
|
115
|
-
const el = findChild(node, "const_element");
|
|
116
|
-
const name = el ? namedChildren(el)[0]?.text : null;
|
|
117
|
-
if (!name)
|
|
118
|
-
return null;
|
|
119
|
-
const vis = phpVisibility(node);
|
|
120
|
-
return makeSymbol({
|
|
121
|
-
name,
|
|
122
|
-
kind: "const",
|
|
123
|
-
node,
|
|
124
|
-
rawKind: node.type,
|
|
125
|
-
visibility: vis,
|
|
126
|
-
exported: vis === "public",
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
case "property_declaration": {
|
|
130
|
-
const decl = findChild(node, "property_element");
|
|
131
|
-
const name = decl?.text.replace(/\s*=.*$/, "").trim();
|
|
132
|
-
if (!name)
|
|
133
|
-
return null;
|
|
134
|
-
const vis = phpVisibility(node);
|
|
135
|
-
return makeSymbol({
|
|
136
|
-
name,
|
|
137
|
-
kind: "field",
|
|
138
|
-
node,
|
|
139
|
-
rawKind: node.type,
|
|
140
|
-
visibility: vis,
|
|
141
|
-
exported: vis === "public",
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
default:
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
// ─── Import extraction ────────────────────────────────────────────────────────
|
|
149
|
-
// `use App\Models\User;`, grouped `use App\{A, B};`, and require/include calls.
|
|
150
|
-
export function extractImportsPhp(root, _source) {
|
|
151
|
-
const imports = [];
|
|
152
|
-
walk(root, imports, 0);
|
|
153
|
-
return imports;
|
|
154
|
-
}
|
|
155
|
-
function walk(node, out, depth) {
|
|
156
|
-
if (depth > 4)
|
|
157
|
-
return;
|
|
158
|
-
for (const c of namedChildren(node)) {
|
|
159
|
-
if (c.type === "namespace_use_declaration")
|
|
160
|
-
parseUse(c, out);
|
|
161
|
-
else if (c.type === "require_expression" ||
|
|
162
|
-
c.type === "require_once_expression" ||
|
|
163
|
-
c.type === "include_expression" ||
|
|
164
|
-
c.type === "include_once_expression") {
|
|
165
|
-
const str = findString(c);
|
|
166
|
-
if (str)
|
|
167
|
-
out.push({ symbol: "*", from: str, isSideEffect: true });
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
walk(c, out, depth + 1);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
function findString(node) {
|
|
175
|
-
for (const c of namedChildren(node)) {
|
|
176
|
-
if (c.type === "string")
|
|
177
|
-
return c.text.replace(/^['"]|['"]$/g, "");
|
|
178
|
-
const deep = findString(c);
|
|
179
|
-
if (deep)
|
|
180
|
-
return deep;
|
|
181
|
-
}
|
|
182
|
-
return null;
|
|
183
|
-
}
|
|
184
|
-
function parseUse(node, out) {
|
|
185
|
-
let groupBase = null;
|
|
186
|
-
for (const c of namedChildren(node)) {
|
|
187
|
-
if (c.type === "namespace_name")
|
|
188
|
-
groupBase = c.text.replace(/\s+/g, "");
|
|
189
|
-
else if (c.type === "namespace_use_clause") {
|
|
190
|
-
const qn = c.text.replace(/\s+as\s+.*$/, "").replace(/\s+/g, "");
|
|
191
|
-
const alias = /\s+as\s+(\w+)/.exec(c.text)?.[1];
|
|
192
|
-
const leaf = qn.split("\\").pop() ?? qn;
|
|
193
|
-
const imp = { symbol: leaf, from: qn };
|
|
194
|
-
if (alias)
|
|
195
|
-
imp.alias = alias;
|
|
196
|
-
out.push(imp);
|
|
197
|
-
}
|
|
198
|
-
else if (c.type === "namespace_use_group") {
|
|
199
|
-
for (const g of namedChildren(c)) {
|
|
200
|
-
if (g.type !== "namespace_use_group_clause")
|
|
201
|
-
continue;
|
|
202
|
-
const txt = g.text.replace(/\s+/g, "");
|
|
203
|
-
const leaf = txt.split("\\").pop() ?? txt;
|
|
204
|
-
out.push({ symbol: leaf, from: groupBase ? `${groupBase}\\${txt}` : txt });
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
}
|
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import { namedChildren, nameOf, headerSignature } from "../parser.js";
|
|
2
|
-
import { makeSymbol, pythonVisibility } from "./common.js";
|
|
3
|
-
export function extractPython(root, _source) {
|
|
4
|
-
return collect(namedChildren(root), false);
|
|
5
|
-
}
|
|
6
|
-
function collect(nodes, insideClass) {
|
|
7
|
-
const out = [];
|
|
8
|
-
for (const n of nodes) {
|
|
9
|
-
const res = handle(n, insideClass);
|
|
10
|
-
if (res)
|
|
11
|
-
out.push(res);
|
|
12
|
-
}
|
|
13
|
-
return out;
|
|
14
|
-
}
|
|
15
|
-
function handle(node, insideClass) {
|
|
16
|
-
if (node.type === "decorated_definition") {
|
|
17
|
-
const inner = innerDefinition(node);
|
|
18
|
-
if (!inner)
|
|
19
|
-
return null;
|
|
20
|
-
const sym = handle(inner, insideClass);
|
|
21
|
-
if (sym) {
|
|
22
|
-
const decs = namedChildren(node)
|
|
23
|
-
.filter((c) => c.type === "decorator")
|
|
24
|
-
.map((d) => d.text.replace(/^@\s*/, "").replace(/\s+/g, " ").trim())
|
|
25
|
-
.filter((t) => t.length > 0);
|
|
26
|
-
if (decs.length > 0)
|
|
27
|
-
sym.decorators = decs;
|
|
28
|
-
}
|
|
29
|
-
return sym;
|
|
30
|
-
}
|
|
31
|
-
if (node.type === "class_definition") {
|
|
32
|
-
const name = nameOf(node) ?? "(class)";
|
|
33
|
-
const body = node.childForFieldName("body");
|
|
34
|
-
const children = body ? collect(namedChildren(body), true) : [];
|
|
35
|
-
return makeSymbol({
|
|
36
|
-
name,
|
|
37
|
-
kind: "class",
|
|
38
|
-
node,
|
|
39
|
-
rawKind: node.type,
|
|
40
|
-
visibility: pythonVisibility(name),
|
|
41
|
-
exported: pythonVisibility(name) === "public",
|
|
42
|
-
doc: body ? docstring(body) : null,
|
|
43
|
-
children,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
if (node.type === "function_definition") {
|
|
47
|
-
const name = nameOf(node) ?? "(function)";
|
|
48
|
-
const body = node.childForFieldName("body");
|
|
49
|
-
return makeSymbol({
|
|
50
|
-
name,
|
|
51
|
-
kind: insideClass ? "method" : "function",
|
|
52
|
-
node,
|
|
53
|
-
rawKind: node.type,
|
|
54
|
-
signature: headerSignature(node, body),
|
|
55
|
-
visibility: pythonVisibility(name),
|
|
56
|
-
exported: pythonVisibility(name) === "public",
|
|
57
|
-
doc: body ? docstring(body) : null,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
function innerDefinition(decorated) {
|
|
63
|
-
const byField = decorated.childForFieldName("definition");
|
|
64
|
-
if (byField)
|
|
65
|
-
return byField;
|
|
66
|
-
for (const c of namedChildren(decorated)) {
|
|
67
|
-
if (c.type === "function_definition" || c.type === "class_definition")
|
|
68
|
-
return c;
|
|
69
|
-
}
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
|
-
// ─── Import extraction ────────────────────────────────────────────────────────
|
|
73
|
-
export function extractImportsPython(root, _source) {
|
|
74
|
-
const imports = [];
|
|
75
|
-
for (const child of namedChildren(root)) {
|
|
76
|
-
if (child.type === "import_statement")
|
|
77
|
-
parseSimpleImport(child, imports);
|
|
78
|
-
else if (child.type === "import_from_statement")
|
|
79
|
-
parseFromImport(child, imports);
|
|
80
|
-
}
|
|
81
|
-
return imports;
|
|
82
|
-
}
|
|
83
|
-
function parseSimpleImport(node, out) {
|
|
84
|
-
for (let i = 0; i < node.namedChildCount; i++) {
|
|
85
|
-
const c = node.namedChild(i);
|
|
86
|
-
if (!c)
|
|
87
|
-
continue;
|
|
88
|
-
if (c.type === "dotted_name" || c.type === "identifier") {
|
|
89
|
-
out.push({ symbol: c.text, from: c.text });
|
|
90
|
-
}
|
|
91
|
-
else if (c.type === "aliased_import") {
|
|
92
|
-
const nameNode = c.childForFieldName("name");
|
|
93
|
-
const aliasNode = c.childForFieldName("alias");
|
|
94
|
-
if (nameNode) {
|
|
95
|
-
const imp = { symbol: nameNode.text, from: nameNode.text };
|
|
96
|
-
if (aliasNode)
|
|
97
|
-
imp.alias = aliasNode.text;
|
|
98
|
-
out.push(imp);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
/**
|
|
104
|
-
* Convert Python import path to a JS-style relative path.
|
|
105
|
-
* ".models" → "./models", "..utils" → "../utils", "os" → "os" (external).
|
|
106
|
-
*/
|
|
107
|
-
function pythonFromPath(raw) {
|
|
108
|
-
const m = raw.match(/^(\.+)(.*)/);
|
|
109
|
-
if (!m)
|
|
110
|
-
return raw; // absolute/external import
|
|
111
|
-
const dotCount = m[1].length;
|
|
112
|
-
const rest = m[2]; // module name after the dots, e.g. "models" or ""
|
|
113
|
-
const upDirs = dotCount === 1 ? "." : Array(dotCount - 1).fill("..").join("/");
|
|
114
|
-
return rest ? `${upDirs}/${rest.replace(/\./g, "/")}` : upDirs;
|
|
115
|
-
}
|
|
116
|
-
function parseFromImport(node, out) {
|
|
117
|
-
const moduleNode = node.childForFieldName("module_name");
|
|
118
|
-
const from = moduleNode ? pythonFromPath(moduleNode.text) : ".";
|
|
119
|
-
for (let i = 0; i < node.namedChildCount; i++) {
|
|
120
|
-
const c = node.namedChild(i);
|
|
121
|
-
if (!c || c === moduleNode)
|
|
122
|
-
continue;
|
|
123
|
-
if (c.type === "wildcard_import") {
|
|
124
|
-
out.push({ symbol: "*", from, isNamespaceImport: true });
|
|
125
|
-
}
|
|
126
|
-
else if (c.type === "relative_import" || c.type === "dotted_name") {
|
|
127
|
-
// skip — these are part of the module path, not the imported names
|
|
128
|
-
}
|
|
129
|
-
else if (c.type === "identifier") {
|
|
130
|
-
out.push({ symbol: c.text, from });
|
|
131
|
-
}
|
|
132
|
-
else if (c.type === "aliased_import") {
|
|
133
|
-
const nameNode = c.childForFieldName("name");
|
|
134
|
-
const aliasNode = c.childForFieldName("alias");
|
|
135
|
-
if (nameNode) {
|
|
136
|
-
const imp = { symbol: nameNode.text, from };
|
|
137
|
-
if (aliasNode)
|
|
138
|
-
imp.alias = aliasNode.text;
|
|
139
|
-
out.push(imp);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
/** Extract a leading triple-quoted docstring from a `block`. */
|
|
145
|
-
function docstring(body) {
|
|
146
|
-
const first = body.namedChild(0);
|
|
147
|
-
if (!first || first.type !== "expression_statement")
|
|
148
|
-
return null;
|
|
149
|
-
const str = first.namedChild(0);
|
|
150
|
-
if (!str || str.type !== "string")
|
|
151
|
-
return null;
|
|
152
|
-
return str.text.replace(/^[rbuRBU]*("""|'''|"|')/, "").replace(/("""|'''|"|')$/, "").trim().slice(0, 500);
|
|
153
|
-
}
|