@brunobrise/xfeat 1.3.0 → 1.4.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/.github/workflows/ci.yml +12 -12
- package/.vscode/settings.json +1 -1
- package/README.md +7 -2
- package/index.js +13 -3
- package/index.test.js +26 -0
- package/package.json +2 -1
package/.github/workflows/ci.yml
CHANGED
|
@@ -2,9 +2,9 @@ name: CI
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
|
-
branches: [
|
|
5
|
+
branches: ["main"]
|
|
6
6
|
pull_request:
|
|
7
|
-
branches: [
|
|
7
|
+
branches: ["main"]
|
|
8
8
|
|
|
9
9
|
jobs:
|
|
10
10
|
build:
|
|
@@ -15,13 +15,13 @@ jobs:
|
|
|
15
15
|
node-version: [18.x, 20.x]
|
|
16
16
|
|
|
17
17
|
steps:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
20
|
+
uses: actions/setup-node@v4
|
|
21
|
+
with:
|
|
22
|
+
node-version: ${{ matrix.node-version }}
|
|
23
|
+
cache: "npm"
|
|
24
|
+
- run: npm ci
|
|
25
|
+
- run: npm run lint
|
|
26
|
+
- run: npm test
|
|
27
|
+
- run: npm audit --audit-level=critical
|
package/.vscode/settings.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{}
|
|
1
|
+
{}
|
package/README.md
CHANGED
|
@@ -11,11 +11,15 @@
|
|
|
11
11
|
- **Agentic Source Code Reading:** Rather than guessing based off function identifiers, the AI utilizes a specialized `view_file` tool to selectively dive into the raw source code wherever AST context is insufficient.
|
|
12
12
|
- **Automated Mermaid Diagrams:** Visually maps out how files interact at macro and global architecture levels.
|
|
13
13
|
- **Structured Markdown Deliverables:** Produces a neat, hierarchical `FEATURES.md` report encompassing everything from the executive summary to granular file logic.
|
|
14
|
-
- **Smart Directory Traversal:** Adheres to your local `.gitignore` rules to avoid processing build artifacts and generic dependencies.
|
|
14
|
+
- **Smart Directory Traversal:** Adheres to your local `.gitignore` and optional custom `.xfeatignore` rules to avoid processing build artifacts and generic dependencies.
|
|
15
15
|
|
|
16
16
|
## How It Works
|
|
17
17
|
|
|
18
|
-
The engine executes in an expanding
|
|
18
|
+
The engine executes in an expanding 4-stage pipeline:
|
|
19
|
+
|
|
20
|
+
0. **AI Pre-filtering (Stage 0):**
|
|
21
|
+
- Interactively requests permission to AI-filter the target files.
|
|
22
|
+
- Cleans the file list by intelligently removing trivial boilerplate, config files, and UI assets dynamically, saving time and tokens.
|
|
19
23
|
|
|
20
24
|
1. **Micro Analysis (File-Level):**
|
|
21
25
|
- Identifies granular structural signatures across source files.
|
|
@@ -94,6 +98,7 @@ The foundational Tree-sitter AST parser natively understands:
|
|
|
94
98
|
- TypeScript (`.ts`, `.tsx`)
|
|
95
99
|
- Python (`.py`)
|
|
96
100
|
- Rust (`.rs`)
|
|
101
|
+
- Go (`.go`)
|
|
97
102
|
|
|
98
103
|
## License
|
|
99
104
|
|
package/index.js
CHANGED
|
@@ -165,7 +165,8 @@ async function extractStructure(filePath) {
|
|
|
165
165
|
const isClass =
|
|
166
166
|
type.includes("class") ||
|
|
167
167
|
type.includes("struct") ||
|
|
168
|
-
type.includes("interface")
|
|
168
|
+
type.includes("interface") ||
|
|
169
|
+
type === "type_spec";
|
|
169
170
|
const isFunction =
|
|
170
171
|
type.includes("function") ||
|
|
171
172
|
type.includes("method") ||
|
|
@@ -180,8 +181,14 @@ async function extractStructure(filePath) {
|
|
|
180
181
|
if (isClass) {
|
|
181
182
|
const nameNode =
|
|
182
183
|
node.childForFieldName("name") ||
|
|
183
|
-
node.children.find((c) => c.type === "identifier")
|
|
184
|
-
|
|
184
|
+
node.children.find((c) => c.type === "identifier") ||
|
|
185
|
+
node.children.find((c) => c.type === "type_identifier");
|
|
186
|
+
if (nameNode) {
|
|
187
|
+
structure.classes.push(nameNode.text);
|
|
188
|
+
if (ext === ".go" && /^[A-Z]/.test(nameNode.text)) {
|
|
189
|
+
structure.exports.push(nameNode.text);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
185
192
|
}
|
|
186
193
|
|
|
187
194
|
if (isFunction) {
|
|
@@ -190,6 +197,9 @@ async function extractStructure(filePath) {
|
|
|
190
197
|
node.children.find((c) => c.type === "identifier");
|
|
191
198
|
if (nameNode && !nameNode.text.startsWith("__")) {
|
|
192
199
|
structure.functions.push(nameNode.text);
|
|
200
|
+
if (ext === ".go" && /^[A-Z]/.test(nameNode.text)) {
|
|
201
|
+
structure.exports.push(nameNode.text);
|
|
202
|
+
}
|
|
193
203
|
}
|
|
194
204
|
}
|
|
195
205
|
|
package/index.test.js
CHANGED
|
@@ -53,6 +53,17 @@ def py_function():
|
|
|
53
53
|
`,
|
|
54
54
|
);
|
|
55
55
|
|
|
56
|
+
await fs.writeFile(
|
|
57
|
+
path.join(testDir, "sample.go"),
|
|
58
|
+
`
|
|
59
|
+
package main
|
|
60
|
+
import "fmt"
|
|
61
|
+
type MyGoStruct struct {}
|
|
62
|
+
func (m *MyGoStruct) GoMethod() {}
|
|
63
|
+
func GoFunction() {}
|
|
64
|
+
`,
|
|
65
|
+
);
|
|
66
|
+
|
|
56
67
|
await fs.writeFile(path.join(testDir, "unsupported.txt"), "Hello world");
|
|
57
68
|
|
|
58
69
|
// Initialize TreeSitter before testing extraction
|
|
@@ -132,6 +143,21 @@ def py_function():
|
|
|
132
143
|
expect(structure.functions).toContain("rs_function");
|
|
133
144
|
});
|
|
134
145
|
|
|
146
|
+
it("should extract AST structure for Go files", async () => {
|
|
147
|
+
const goFilePath = path.join(testDir, "sample.go");
|
|
148
|
+
const structure = await extractStructure(goFilePath);
|
|
149
|
+
|
|
150
|
+
expect(structure).not.toBeNull();
|
|
151
|
+
expect(structure.file).toBe(goFilePath);
|
|
152
|
+
expect(structure.classes).toContain("MyGoStruct");
|
|
153
|
+
expect(structure.functions).toContain("GoMethod");
|
|
154
|
+
expect(structure.functions).toContain("GoFunction");
|
|
155
|
+
expect(structure.exports).toContain("MyGoStruct");
|
|
156
|
+
expect(structure.exports).toContain("GoMethod");
|
|
157
|
+
expect(structure.exports).toContain("GoFunction");
|
|
158
|
+
expect(structure.imports).toContain('"fmt"');
|
|
159
|
+
});
|
|
160
|
+
|
|
135
161
|
it("should return null for unsupported file extensions", async () => {
|
|
136
162
|
const txtFilePath = path.join(testDir, "unsupported.txt");
|
|
137
163
|
const structure = await extractStructure(txtFilePath);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brunobrise/xfeat",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Automated AI-driven CLI for codebase analysis and feature extraction.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"map-stream": "^0.0.7",
|
|
43
43
|
"tree-sitter-bash": "^0.25.1",
|
|
44
44
|
"tree-sitter-css": "^0.25.0",
|
|
45
|
+
"tree-sitter-go": "^0.25.0",
|
|
45
46
|
"tree-sitter-html": "^0.23.2",
|
|
46
47
|
"tree-sitter-javascript": "^0.25.0",
|
|
47
48
|
"tree-sitter-json": "^0.24.8",
|