Skip to content

Commit

Permalink
Add full source map support to line number selection
Browse files Browse the repository at this point in the history
  • Loading branch information
novemberborn committed Oct 4, 2021
1 parent 76c0170 commit 0e7ef69
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 24 deletions.
1 change: 1 addition & 0 deletions .xo-config.json
Expand Up @@ -2,6 +2,7 @@
"ignores": [
"media/**",
"test/config/fixtures/config-errors/test.js",
"test/line-numbers/fixtures/line-numbers.js",
"test-tap/fixture/snapshots/test-sourcemaps/build/**",
"test-tap/fixture/report/edgecases/ast-syntax-error.cjs",
"examples/typescript-*/**/*.ts"
Expand Down
42 changes: 36 additions & 6 deletions lib/worker/line-numbers.js
@@ -1,5 +1,5 @@
import * as fs from 'node:fs';
import {createRequire} from 'node:module';
import {createRequire, findSourceMap} from 'node:module';
import {pathToFileURL} from 'node:url';

import callsites from 'callsites';
Expand Down Expand Up @@ -60,15 +60,45 @@ function findTest(locations, declaration) {

const range = (start, end) => Array.from({length: end - start + 1}).fill(start).map((element, index) => element + index);

const translate = (sourceMap, pos) => {
if (sourceMap === undefined) {
return pos;
}

const entry = sourceMap.findEntry(pos.line - 1, pos.column); // Source maps are 0-based
return {
line: entry.originalLine + 1, // Readjust for Acorn.
column: entry.originalColumn,
};
};

export default function lineNumberSelection({file, lineNumbers = []}) {
if (lineNumbers.length === 0) {
return undefined;
}

const locations = parse(file);
const selected = new Set(lineNumbers);

let locations = parse(file);
let lookedForSourceMap = false;
let sourceMap;

return () => {
if (!lookedForSourceMap) {
lookedForSourceMap = true;

// The returned function is called *after* the file has been loaded.
// Source maps are not available before then.
sourceMap = findSourceMap(file);

if (sourceMap !== undefined) {
locations = locations.map(({start, end}) => ({
start: translate(sourceMap, start),
end: translate(sourceMap, end),
}));
}
}

// Assume this is called from a test declaration, which is located in the file.
// If not… don't select the test!
const callSite = callsites().find(callSite => {
Expand All @@ -83,10 +113,10 @@ export default function lineNumberSelection({file, lineNumbers = []}) {
return false;
}

const start = {
line: callSite.getLineNumber(),
column: callSite.getColumnNumber() - 1, // Use 0-indexed columns.
};
const start = translate(sourceMap, {
line: callSite.getLineNumber(), // 1-based
column: callSite.getColumnNumber() - 1, // Comes out as 1-based, Acorn wants 0-based
});

const test = findTest(locations, start);
if (!test) {
Expand Down
5 changes: 5 additions & 0 deletions test/line-numbers/fixtures/README.md
@@ -0,0 +1,5 @@
Compile using:

```console
npx tsc line-numbers.ts --outDir . --sourceMap --module es2020 --moduleResolution node
```
32 changes: 14 additions & 18 deletions test/line-numbers/fixtures/line-numbers.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions test/line-numbers/fixtures/line-numbers.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions test/line-numbers/fixtures/line-numbers.ts
@@ -0,0 +1,27 @@
import test from 'ava'; // eslint-disable-line ava/no-ignored-test-files

test('unicorn', t => {
t.pass();
});

test('rainbow', t => {
t.pass();
});

test.serial('cat', t => {
t.pass();
});

test.todo('dog'); // eslint-disable-line ava/no-todo-test

/* eslint-disable max-statements-per-line, ava/no-inline-assertions */
test('sun', t => t.pass()); test('moon', t => {
t.pass();
});
/* eslint-enable max-statements-per-line, ava/no-inline-assertions */

(() => {
test('nested call', t => {
t.pass();
});
})();

0 comments on commit 0e7ef69

Please sign in to comment.