Closed novemberborn closed 2 years ago
Current implementation of @ava/babel
manages source map through its worker()
method. It installs source-map-support
at line https://github.com/avajs/babel/blob/0949eaadfff2c7f8009f056c62c5f632ff7f0c6d/index.js#L359
I think it is good to move source map management functionality to AVA. So the providers can focus to:
canParse(file)
to check if the provider can parse the given fileBy moving source map management to AVA, we will get more flexibility to manage the stack trace. Maybe we could create new file source-map-manager.js
which wraps source-map-support
functionality. The implementation of source-map-support
internally modifies the Error.prepareStackTrace
https://github.com/evanw/node-source-map-support/blob/d29e9c81527346b6ec385f7ba27a7a1c487b69c7/source-map-support.js#L563 to generate original stack trace. In the future we could replace source-map-support
with explicit implementation to solve https://github.com/avajs/ava/issues/2474
The source-map-manager.js
is not coupled with test worker, so we also can use it in main process as long as the state
of compiled source which hold source map location is provided https://github.com/avajs/ava/blob/78cfaa17fec615a1979a9aaa9855f6cc8eeeb4d8/lib/api.js#L194-L197
Example of source map manager usage:
const SourceMapManager = require('./source-map-manager');
const sourceMapManager = await new SourceMapManager({
defaultStackTraceInference: 'compiled-stack'
});
sourceMapManager.installSourceMapHandler();
sourceMapManager.addState(state); // register `state` which is generated by provider, where `source-map-manager` could find the source map file
// this can be used to replace `const sourceCallSite = sourceMapSupport.wrapCallSite(callSite);` in `worker/line-numbers.js`
// it will decide which source map to use and return original frame
sourceMapManager.getOriginalFrame(frame);
sourceMapManager.enableOriginalStackTrace(); // enable source map manager to infer original stack
const originalStack = (new Error('foo')).stack
sourceMapManager.disableOriginalStackTrace(); // leave source map manager to infer from compiled source again
// maybe also expose some lower level methods such as methods found in `SourceMapConsumer`
We can pass sourceMapManager
to lineNumberSelection()
along with providers
so we can use to make line number selection work.
const getParser = providers => {
for (const provider of providers) {
if (provider.canParse(file)) {
return provider.parse;
}
}
// no provider can handle. use default
return parse;
}
parse = getParser(providers);
const locations = parse(file);
// omitted lines
// ......
return () => {
// omitted lines
// .....
const sourceCallSite = sourceMapManager.getOriginalFrame(callSite);
const start = {
line: sourceCallSite.getLineNumber(),
column: sourceCallSite.getColumnNumber() - 1
};
const test = findTest(locations, start);
// omitted lines
// .....
}
In the future maybe we could add more providers such as coffee-script
etc. Correct me if my interpretation is wrong.
I think it is good to move source map management functionality to AVA.
@okyantoro yes, see arno https://github.com/avajs/ava/issues/2474.
That said I'd prefer using a language specific AST to determine the line numbers.
In the future maybe we could add more providers such as
coffee-script
etc. Correct me if my interpretation is wrong.
I don't think it's wrong. AVA itself can focus on Node.js support, and other languages / dialects can be handled through providers. However we have limited resources and should refrain from supporting esoteric platforms.
I hit this issue/#2474 yesterday with some tests I wrote in Typescript, and worked around it by using Babel to transpile my Typescript into Javascript for AVA to execute. It's... clunky. I see both issues are labelled help wanted
- what help is needed at this point?
@alastairs I think the issue description is still accurate. Happy to help if you're getting stuck anywhere in particular.
AVA 4 removes @ava/babel
. I think https://github.com/avajs/ava/pull/2859 may have fixed this issue for TypeScript.
Line number selection relies on AVA parsing the test file. This does not work when you use a require hook (such as
ts-node/register
). That's OK. However we do want it to work with our Babel and TypeScript providers.Ultimately, we need start and end lines & columns for each call expression in the test file. First we need to initialize the providers earlier:
https://github.com/avajs/ava/blob/1222ce9538e4890c20af695e558e3ee490f5a41b/lib/worker/subprocess.js#L45-L52
See here:
https://github.com/avajs/ava/blob/1222ce9538e4890c20af695e558e3ee490f5a41b/lib/worker/subprocess.js#L140-L159
Then, depending on the extension of the test file, we need to get the provider to give us the call locations. For normal JS files you can find that logic here:
https://github.com/avajs/ava/blob/1222ce9538e4890c20af695e558e3ee490f5a41b/lib/worker/line-numbers.js#L1-L28
For
@ava/babel
we need to parse the test file using Babel, with all the configured plugins active and whatnot.For
@ava/typescript
, hopefully we can usetypescript
itself as a parser?