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
11 changes: 11 additions & 0 deletions plugins/axiomcode/skills/axiomcode/scripts/axiomcode-path
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,11 @@ class G:
if p == root or p.startswith(root.rstrip('/') + '/'):
return os.path.relpath(p, root).replace(os.sep, '/'), False
return f.lstrip('/'), True
def file_lines(self, f):
"""how many lines the indexed file `f` has on disk, or None when it cannot be read there"""
try:
with open(os.path.join(self.repo, f), 'rb') as h: return len(h.read().splitlines())
except OSError: return None
def _resolve(self, sel, fragment=False):
s = sel.strip().strip('`"\'')
# file:line, or file:line:col as a stack trace prints it — the column never changes which callable spans the line
Expand All @@ -340,6 +345,12 @@ class G:
if len(files) > 12: rows.append(f" … +{len(files) - 12} more")
die(f"'{m.group(1)}' matches {len(files)} indexed files — give enough of the path to name one:\n" + '\n'.join(rows))
if files: f = files[0]
# A LINE OUTSIDE THE FILE IS REFUSED (#1601). Line 0, or a line past the end — a number copied before the file
# was edited, or from an old stack trace — spans no callable, so it fell through to the module node and was
# answered as the file's top-level code, as if that line existed. The file on disk is what the reader sees.
if ln < 1: die(f"line {ln} is not in {f}: lines are numbered from 1")
n = self.file_lines(f) if files else None
if n is not None and ln > n: die(f"{f} has {n} line{'' if n == 1 else 's'}; line {ln} is not in it")
# the smallest callable(s) spanning the line — several when they share it (`class Item { run(){} tag(){} }`);
# top-level code belongs to the file's module node, which is a caller like any other
r = self.q("SELECT id, end_line - line AS span FROM symbols WHERE file = ? AND line <= ? AND end_line >= ? AND method_id IS NOT NULL AND kind <> 'module' ORDER BY span", f, ln, ln)
Expand Down
42 changes: 42 additions & 0 deletions tests/cases/javascript/fileline-line-outside-file/case.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{"lang": "javascript",
"checks": [
{"why": "a line past the end of the file is refused with the file's length, not answered as its top-level code (#1601)",
"run": ["impact", "src/services/userService.js:99"],
"expect_error": true,
"want": ["src/services/userService.js has 4 lines; line 99 is not in it"],
"avoid": ["<module>"]},
{"why": "line 0 is refused too",
"run": ["impact", "src/services/userService.js:0"],
"expect_error": true,
"want": ["line 0 is not in src/services/userService.js"],
"avoid": ["<module>"]},
{"why": "the same through path",
"run": ["path", "*", "src/services/userService.js:0"],
"expect_error": true,
"want": ["line 0 is not in src/services/userService.js"],
"avoid": ["0 method(s)"]},
{"why": "the line just past the end, through path, with a partial undotted file name",
"run": ["path", "*", "services/userService.js:5"],
"expect_error": true,
"want": ["src/services/userService.js has 4 lines; line 5 is not in it"],
"avoid": ["0 method(s)"]},
{"why": "a file with no newline at its end: the line after its last is refused",
"run": ["impact", "app.js:3"],
"expect_error": true,
"want": ["src/app.js has 2 lines; line 3 is not in it"]},
{"why": "control: the last line of a file with no newline at its end is still its top-level code",
"run": ["impact", "src/app.js:2"],
"want": ["app.<module> (at src/app.js:2)"],
"avoid": ["is not in it"]},
{"why": "control: the last line, top-level code, still answers as the module",
"run": ["impact", "src/services/userService.js:4"],
"want": ["userService.<module> (at src/services/userService.js:4)"],
"avoid": ["is not in it"]},
{"why": "control: a line inside a function still answers for that function, with its caller",
"run": ["path", "*", "src/services/userService.js:2"],
"want": ["getUser"],
"avoid": ["is not in it"]},
{"why": "control: a file the index does not hold is still refused as before",
"run": ["impact", "zzz/userService.js:99"],
"expect_error": true,
"want": ["no callable spans zzz/userService.js:99"]}]}
2 changes: 2 additions & 0 deletions tests/cases/javascript/fileline-line-outside-file/src/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
const { getUser } = require('./services/userService');
getUser(1);
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exports.find = function (id) { return { id }; };
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const db = require('../db');
function getUser(id) { return db.find(id); }
module.exports = { getUser };
// last line
Loading