Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions plugins/axiomcode/skills/axiomcode/scripts/axiomcode-path
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,22 @@ class G:
# body's), and the first row came back whatever the line, so a module-level constant below a class was
# answered as that class's body
r = self.q("SELECT id FROM symbols WHERE file = ? AND kind = 'module' AND method_id IS NOT NULL ORDER BY (line <= ? AND COALESCE(end_line, line) >= ?) DESC, COALESCE(end_line, line) - line LIMIT 1", f, ln, ln)
# A LINE INSIDE A TYPE'S BODY BUT IN NONE OF ITS MEMBERS is not top-level code. A blank or comment line between
# two methods — a line number copied before the file was edited — was answered as the whole file's module
# where a class body has no module node of its own (TypeScript, Java, C#), with no word that the line holds
# nothing. A Python class body IS a module node inside the type, and still answers as before.
ty = self.q("SELECT id, display, line, end_line FROM symbols WHERE file = ? AND type_id IS NOT NULL AND method_id IS NULL AND line < ? AND end_line > ? ORDER BY end_line - line LIMIT 1", f, ln, ln)
mod = self.sym.get(r[0]['id'], {}) if r else {}
if ty and not (r and ty[0]['line'] <= (mod.get('line') or 0) and (mod.get('end_line') or 0) <= ty[0]['end_line']):
t = ty[0]
mem = self.q("SELECT id, line, end_line FROM symbols WHERE file = ? AND line > ? AND end_line < ? AND kind <> 'module' AND (method_id IS NOT NULL OR kind IN ('field','const','enum_member','variable'))", f, t['line'], t['end_line'])
above = max((x for x in mem if (x['end_line'] or x['line']) < ln), key=lambda x: (x['end_line'] or x['line'], -x['line']), default=None)
below = min((x for x in mem if x['line'] > ln), key=lambda x: (x['line'], x['line'] - (x['end_line'] or x['line'])), default=None)
near = [f" {self.name(x['id'])} {f}:{x['line']}" for x in (above, below) if x]
die(f"line {ln} of {f} is inside {t['display']} ({f}:{t['line']}-{t['end_line']}) but in none of its declarations"
" (a blank, comment or separator line — often a line number from before an edit)."
+ ("\n the nearest declarations:\n" + '\n'.join(near) if near else '')
+ f"\n ask for one of them, by name or by its line; `{t['display']}` asks about the whole type")
if r: return f"{self.disp(r[0]['id'])} (top-level code at {s})", [r[0]['id']]
if outside: die(f"{m.group(1)} is outside the indexed repository {self.repo}: give the file relative to that root, or ask the graph of the repository it belongs to")
die(f"no callable spans {s}")
Expand Down
13 changes: 13 additions & 0 deletions tests/cases/javascript/fileline-line-outside-file/case.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@
"run": ["path", "*", "src/services/userService.js:2"],
"want": ["getUser"],
"avoid": ["is not in it"]},
{"why": "a blank line between two members of a class is refused with the members either side, not answered as the file's top-level code",
"run": ["impact", "src/services/cart.js:3"],
"expect_error": true,
"want": ["line 3 of src/services/cart.js is inside Cart", "Cart.add src/services/cart.js:5"],
"avoid": ["<module>"]},
{"why": "control: the class header line still answers for the class",
"run": ["impact", "src/services/cart.js:1"],
"want": ["Cart"],
"avoid": ["is inside Cart", "change: cart.<module>"]},
{"why": "control: the line after the class is still the file's top-level code",
"run": ["impact", "src/services/cart.js:7"],
"want": ["cart.<module> (at src/services/cart.js:7)"],
"avoid": ["is inside Cart"]},
{"why": "control: a file the index does not hold is still refused as before",
"run": ["impact", "zzz/userService.js:99"],
"expect_error": true,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class Cart {
constructor() { this.items = []; }

/** adds one */
add(x) { this.items.push(x); }
}
new Cart().add('a');
module.exports = { Cart };
20 changes: 19 additions & 1 deletion tests/cases/typescript/fileline-dotted-basename/case.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,22 @@
{"why": "path takes a ./ file:line",
"run": ["path", "*", "./src/user.service.ts:3"],
"want": ["UserController.get"],
"avoid": ["no callable spans"]}]}
"avoid": ["no callable spans"]},
{"why": "a blank line inside a class body, between two members, is refused with the members either side, not answered as the file's top-level code",
"run": ["impact", "src/cart.ts:3"],
"expect_error": true,
"want": ["line 3 of src/cart.ts is inside Cart", "Cart.add src/cart.ts:5"],
"avoid": ["<module>"]},
{"why": "the same for a member's doc-comment line, through path",
"run": ["path", "*", "src/cart.ts:4"],
"expect_error": true,
"want": ["line 4 of src/cart.ts is inside Cart", "Cart.add src/cart.ts:5"],
"avoid": ["top-level code"]},
{"why": "control: the member's own line still answers for it",
"run": ["impact", "src/cart.ts:5"],
"want": ["change: Cart.add (at src/cart.ts:5)"],
"avoid": ["is inside Cart"]},
{"why": "control: a line after the class is still the file's top-level code",
"run": ["impact", "src/cart.ts:7"],
"want": ["cart.<module> (at src/cart.ts:7)"],
"avoid": ["is inside Cart"]}]}
7 changes: 7 additions & 0 deletions tests/cases/typescript/fileline-dotted-basename/src/cart.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export class Cart {
private items: string[] = [];

/** adds one */
add(x: string): void { this.items.push(x); }
}
new Cart().add('a');
Loading