ast-search-python 1.1.2 → 1.3.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/AGENTS.md +11 -3
- package/README.md +1 -1
- package/build/query.js +1 -1
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -14,7 +14,8 @@ ast-search <query> --plugin ast-search-python [--dir <path>] [--format text|json
|
|
|
14
14
|
|------|-------|---------|-------------|
|
|
15
15
|
| `--plugin` | `-p` | — | Must be `ast-search-python` to activate Python support |
|
|
16
16
|
| `--dir` | `-d` | `cwd` | Root directory to search |
|
|
17
|
-
| `--format` | `-f` | `text` | Output format: `text`, `json`, or `
|
|
17
|
+
| `--format` | `-f` | `text` | Output format: `text`, `json`, `files`, or `count` |
|
|
18
|
+
| `--exclude` | `-x` | none | Glob pattern(s) to exclude from search (repeatable) |
|
|
18
19
|
| `--lang` | `-l` | all | Pass `python` to restrict to Python files only |
|
|
19
20
|
| `--context` | `-C` | `0` | Show N lines of context around each match (like `grep -C`) |
|
|
20
21
|
| `--ast` | — | off | Print Python AST for a snippet or `--file`; requires `--lang python` |
|
|
@@ -83,13 +84,15 @@ Text output appends captures after the source line:
|
|
|
83
84
|
src/app.py:5:0: logging.info("user logged in") | fn=logging.info msg="user logged in" call=logging.info("user logged in")
|
|
84
85
|
```
|
|
85
86
|
|
|
86
|
-
JSON output includes
|
|
87
|
+
JSON output includes `start`/`end` byte offsets and `source_full` (for multi-line matches) in addition to `captures`:
|
|
87
88
|
|
|
88
89
|
```json
|
|
89
90
|
{
|
|
90
91
|
"file": "src/app.py",
|
|
91
92
|
"line": 5,
|
|
92
93
|
"col": 0,
|
|
94
|
+
"start": 87,
|
|
95
|
+
"end": 116,
|
|
93
96
|
"source": "logging.info(\"user logged in\")",
|
|
94
97
|
"captures": {
|
|
95
98
|
"fn": "logging.info",
|
|
@@ -99,6 +102,11 @@ JSON output includes a `captures` field when captures are present:
|
|
|
99
102
|
}
|
|
100
103
|
```
|
|
101
104
|
|
|
105
|
+
- `start` / `end`: **byte offsets** from the start of the file (not UTF-16 character offsets as in the JS backend). For ASCII-only source these are equivalent; for non-ASCII source (e.g. Unicode identifiers or string literals), byte offsets and character offsets diverge — account for this when slicing file contents.
|
|
106
|
+
- `source_full`: full text of the matched node. Only present when the match spans multiple lines (differs from `source`).
|
|
107
|
+
|
|
108
|
+
⚠️ **Python `start`/`end` are byte offsets; JS/TS `start`/`end` are UTF-16 character offsets.** When writing tools that consume both, use the `file`/`line`/`col` fields for display and treat `start`/`end` as language-specific.
|
|
109
|
+
|
|
102
110
|
All captures from a single pattern application are grouped onto one match — `@fn`, `@msg`, and `@call` from the same query match produce one result, not three.
|
|
103
111
|
|
|
104
112
|
---
|
|
@@ -204,6 +212,6 @@ const matches = await searchRepo('fn', './src');
|
|
|
204
212
|
- **`async def` functions are typed as `function_definition`** in tree-sitter-python 0.21+. There is no separate `async_function_definition` node. The `fn` shorthand matches both. To match only async, use a predicate query.
|
|
205
213
|
- **Shorthands are not expanded inside quoted strings.** `'(call function: (identifier) @n (#eq? @n "fn"))'` keeps `"fn"` literal.
|
|
206
214
|
- **Unparseable files are silently skipped.** Syntax errors in source files do not abort the search.
|
|
207
|
-
- **`node_modules` is always excluded**, as are files/directories whose names start with `.`.
|
|
215
|
+
- **`node_modules` is always excluded**, as are files/directories whose names start with `.`. Use `--exclude` / `-x` for additional patterns (e.g. `--exclude '**/*_test.py'`). Patterns match against paths relative to `--dir`.
|
|
208
216
|
- **Verify the AST structure before writing a query.** Python attribute chains like `self.client.send()` nest deeply — `self` is not the direct `object:` of the outer call; `self.client` is. If a predicate query returns no results, first remove the predicate and confirm the base pattern matches what you expect.
|
|
209
217
|
- **All captures from one pattern match are grouped on a single result.** A query like `(function_definition name: (identifier) @n) @fn` produces one match per function, with both `@fn` and `@n` in the `captures` field. The anchor (location) is the first non-underscore capture — `@fn` in this case.
|
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ ast-search <query> --plugin ast-search-python [--dir <path>] [--format <fmt>] [-
|
|
|
35
35
|
| -------------- | -------------------------------------------------------------- | ----------- |
|
|
36
36
|
| `<query>` | Shorthand or tree-sitter S-expression (see Query Syntax below) | required |
|
|
37
37
|
| `-d, --dir` | Root directory to search | current dir |
|
|
38
|
-
| `-f, --format` | Output format: `text`, `json`, or `
|
|
38
|
+
| `-f, --format` | Output format: `text`, `json`, `files`, or `count` | `text` |
|
|
39
39
|
| `-l, --lang` | Restrict search to `python` only (useful in mixed-language repos) | all languages |
|
|
40
40
|
| `-p, --plugin` | `ast-search-python` | required |
|
|
41
41
|
| `-C, --context` | Show N lines of context around each match (like `grep -C`) | `0` |
|
package/build/query.js
CHANGED
|
@@ -40,7 +40,7 @@ export function runTreeSitterQuery(ast, pattern, source, filePath, language) {
|
|
|
40
40
|
captureMap[cap.name] = source.slice(cap.node.startIndex, cap.node.endIndex);
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
-
results.push(Object.assign({ file: filePath, line: anchor.node.startPosition.row + 1, col: anchor.node.startPosition.column, source: firstLine }, (Object.keys(captureMap).length > 0 ? { captures: captureMap } : {})));
|
|
43
|
+
results.push(Object.assign(Object.assign({ file: filePath, line: anchor.node.startPosition.row + 1, col: anchor.node.startPosition.column, start: anchor.node.startIndex, end: anchor.node.endIndex, source: firstLine }, (text !== firstLine ? { source_full: text } : {})), (Object.keys(captureMap).length > 0 ? { captures: captureMap } : {})));
|
|
44
44
|
}
|
|
45
45
|
return results;
|
|
46
46
|
}
|