-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for TypeScript without precompiling #1122
Conversation
8610723
to
4acb78f
Compare
"xo": "^0.17.0", | ||
"zen-observable": "^0.3.0" | ||
}, | ||
"xo": { | ||
"rules": { | ||
"import/newline-after-import": "off", | ||
"no-use-extend-native/no-use-extend-native": "off" | ||
"no-use-extend-native/no-use-extend-native": "off", | ||
"no-useless-escape": "off" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix the issue instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. fixed.
but this part looks to be a little weird:
var isBabelPath = /^babel-runtime[\\/]?/.test(path.node.value);
Ref: http://stackoverflow.com/a/40315390/1123955
And a question: How did the AVA pass the CI test? I just clone the AVA repo, run npm install && npm t
, XO will throw no-useless-escape
error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's weird, I don't get that failure locally either. Just fix it though.
@@ -0,0 +1,6 @@ | |||
import { test } from 'ava' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import {test} from 'ava';
And use semi-colons.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -89,7 +89,7 @@ | |||
"arr-flatten": "^1.0.1", | |||
"array-union": "^1.0.1", | |||
"array-uniq": "^1.0.2", | |||
"arrify": "^1.0.0", | |||
"arrify": "^1.0.1", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't do unrelated changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok.
@@ -154,7 +154,7 @@ | |||
"resolve-cwd": "^1.0.0", | |||
"semver": "^5.3.0", | |||
"set-immediate-shim": "^1.0.1", | |||
"source-map-support": "^0.4.0", | |||
"source-map-support": "^0.4.5", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just run an npm install arrify source-map-support --save
by mistake
Restored old version.
@@ -0,0 +1,116 @@ | |||
'use strict'; | |||
/** | |||
* AVA File Extention for typescript |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extention => Extension
typescript => TypeScript
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
extTs.register(); | ||
break; | ||
default: | ||
// not supported ext? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should throw an useful error here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
throw new Error('`--extension ' + ext + '` is not supported by AVA.')
runOnlyExclusive: runOnlyExclusive | ||
}).then(function (runStatus) { | ||
}; | ||
if (extensions) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an internal API. We can just make passing the extensions
argument required and drop this if-statement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
@@ -100,6 +103,11 @@ exports.run = function () { | |||
throw new Error(colors.error(figures.cross) + ' The --require and -r flags are deprecated. Requirements should be configured in package.json - see documentation.'); | |||
} | |||
|
|||
if (cli.flags.extension) { | |||
cli.flags.extension = arrify(cli.flags.extension); | |||
cli.flags.extension.push('js'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we discussed in avajs/ava-files#9 (comment), the option should override js
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed to this:
if (cli.flags.extension) {
cli.flags.extension = arrify(cli.flags.extension);
} else {
cli.flags.extension = ['js'];
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't you just do this?
cli.flags.extension = arrify(cli.flags.extension || 'js');
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jedmao great idea, thanks!
@@ -43,6 +43,7 @@ exports.run = function () { | |||
' --source, -S Pattern to match source files so tests can be re-run (Can be repeated)', | |||
' --timeout, -T Set global timeout', | |||
' --concurrency, -c Maximum number of test files running at the same time (EXPERIMENTAL)', | |||
' --extension, -e Set test file extention. `ts` is for Typescript', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test file extension, for example `ts` for TypeScript (Can be repeated)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
// here for other exts in the future | ||
|
||
default: | ||
// not supported(yet) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should throw an useful error here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
throws the same error as the above.
I don't think you pushed your changes. Merge conflict also needs fixing. |
@sindresorhus Yes, I'm still fighting with the unit tests. Because of the new Will push after I fixed them. |
Just finished all the unit tests with the latest code in this PR branch.
Please let me know if I missed anything. :) |
}; | ||
} | ||
|
||
var extTs = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just export this directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
require('source-map-support').install({ | ||
hookRequire: true | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't ts-node
already do this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes and no.
ts-node will do this if we use transpile function from ts-node. However, the current version of lib/ext/ts.js is not using the ts-node by default, it use the raw typescript module, so we have to do this by ourselves.
I leave the ts-node in lib/ext/ts.js is because at the beginning I'm not sure which one is better, so I implement both, but at last I decided to use pure typescript by default:
module.exports = module.exports.default = {
register: typescriptRegister,
transpile: typescriptTranspile,
Do you think we should use ts-node, or I need to get rid of the additional ts-node code in lib/ext/ts.js?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like ts-node
is closer to babel-node
than babel-core
(and ts-node/register
is equivalent to babel-core/register
). IMO this module should just use typescript
to transpile the code, and no other functionality is required.
For consistency we should not automatically transpile source files, at least until we have a better answer for the .js
use case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zixia per the above discusison, could you simplify this module to just the transpile
function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @novemberborn ,
I had simplified this module, removed all the ts-node parts, cleaned the code, but not just the transpile.
The register()
function has to be kept because if we run test written in TypeScript, the lib/test-worker.js must has the ability to transpile TypeScript, which is enabled by extTs.register()
at here: https://github.com/zixia/ava/blob/typescript/lib/test-worker.js#L38
* | ||
* Ts-Node version | ||
* | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zixia very cool!
There's some merge conflicts now, probably because we changed the code to use more ES2015 features. Sorry about that, though on the plus side you get to use ES2015!
@@ -47,8 +48,29 @@ CachingPrecompiler.prototype._init = function () { | |||
CachingPrecompiler.prototype._transform = function (code, filePath, hash) { | |||
code = code.toString(); | |||
|
|||
var options = babelConfigHelper.build(this.babelConfig, this.powerAssert, filePath, code); | |||
var result = this.babel.transform(code, options); | |||
var fileExt = path.extname(filePath).replace(/^\./, ''); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
path.extname(filePath).slice(1)
seems cleaner.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
var fileExt = path.extname(filePath).replace(/^\./, ''); | ||
var isCustomExt = this.extensions.filter(function (ext) { | ||
return (ext !== 'js' && ext === fileExt); | ||
}).length > 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be simplified to:
var isCustomExt = fileExt !== 'js' && this.extensions.indexOf(fileExt) > -1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
} | ||
} | ||
|
||
if (!result) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should just be an else
, assuming the body for if (isCustomExt)
assigns result
or throws.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
typescript = require('typescript'); | ||
} catch (err) { | ||
console.error('AVA: `--extensions=ts` require TypeScript to be installed.'); | ||
throw err; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than logging and then rethrowing the original error construct a new error like in
Line 99 in 0f04001
throw new Error(colors.error(figures.cross) + ' The TAP reporter is not available when using watch mode.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
require('source-map-support').install({ | ||
hookRequire: true | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like ts-node
is closer to babel-node
than babel-core
(and ts-node/register
is equivalent to babel-core/register
). IMO this module should just use typescript
to transpile the code, and no other functionality is required.
For consistency we should not automatically transpile source files, at least until we have a better answer for the .js
use case.
@novemberborn I love ES2015 too. Had just followed your suggestions and resolved all the conflicts. |
var result; | ||
|
||
if (isCustomExt) { | ||
switch (fileExt) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zixia could you change this to an if
statement?
break; | ||
|
||
default: | ||
throw new Error('`--extension ' + fileExt + '` is not supported by AVA.'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's check for allowed extensions in lib/cli
instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had changed to if
.
Where are the allowed extensions in cli.js? Did you mean we should save all supported extensions to an array in cli.js, then reference it in other js files?
require('source-map-support').install({ | ||
hookRequire: true | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zixia per the above discusison, could you simplify this module to just the transpile
function?
}; | ||
} | ||
|
||
module.exports = module.exports.default = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just use exports.transpile = typescriptTranspile
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to keep register()
with tranpile()
, as I described here: #1122 (comment)
If there has any alternative way to do this, please let me know, thanks.
throw new Error('AVA: `--extension=' + ext + '` is not supported by AVA.'); | ||
} | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove these changes. Right now I'd prefer our TypeScript support is consistent with our Babel support, where dependencies are not automatically transpiled.
I know that's not ideal but we can revisit it later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the TypeScript support would still work after we removed those changes. Because if no extTs.register()
, then test-worker.js will not work with .ts test files.
This TypeScript support will only be enabled when we specify --extension ts
arg with AVA, which is the case we need to automatically transpile all TypeScript file with extension: .ts
And about the dependencies, I think for TypeScript is different as for JavaScript, because:
- There are almost no TypeScript dependencies in NPM(node_modules)
- The
.ts
extension is not the default JavaScript file extension, so it's almost only in our development environment.
Please correct me if I'm wrong, or missed anything. Thanks.
Thank you guys for all the replies of this PR. Please let me know if I missed any important replies because this conversation is growing fast. ;-p |
@zixia could you explain why you think
There are none, currently, since Zooming out a bit, @jedmao perhaps we should revisit |
@novemberborn got it. The reason I think I believe that's because my tests have to import pure TypeScript module file: there is all kind of TypeScript files in my source tree, and I never compile them, just Will check them and reply you with the details later. |
Right, that's the same issue we have with our Babel support: source files are not automatically transpiled so users need to add This is by no means ideal, but automatically including I've been playing with performance optimizations in this area (e.g. #1082). Really I'd like to have users opt-in to a particular behavior for their tests and source files, and then have everything be automatic. For now though I'm suggesting we do not automatically load TypeScript when running tests. The behavior would be the same as for users relying on This PR already introduces many subtle changes to AVA's behavior that should be factored out. That's a larger task and I think this PR provides enough value as it stands today, so we should try and land it. But not with automatic TypeScript loading. |
Hi @novemberborn , Got your idea, and thanks for the explanations.
done.
done. I had removed "ava": {
"require": [
"ts-node/register"
]
}, For more about TypeScript register, here's some discussions about it: microsoft/TypeScript#1823 Have a good weekend! |
I found a strange unit test failure in test/cli.js at here: https://github.com/zixia/ava/blob/d7bfa76fb708b6d918f1c821df0417d79e96cde4/test/cli.js#L383 We run I have no idea of it because I did not touch this part this week and everything is ok before. Will check it later. |
Any news about PR ? I'd like to adopt ava in my project, but separate TS precompilation (and as i understand, the ava now just doesn't work with file extensions rather than .js) is huge stopper for me. |
@asvetliakov Before this PR be merged, you can try this new feature by clone the source with $ git clone https://github.com/zixia/ava-files.git
$ cd ava-files
$ npm install && npm link
$ cd ..
$ git clone https://github.com/zixia/ava.git
$ cd ava
$ git checkout typescript
$ npm install & npm link ava-files && npm link Then you can use ava with TypeScripe in your project like: $ cd my-project
$ npm link ava
$ ./node_modules/.bin/ava --extension=ts Please let me know if there's any issue with your project if you have time to try it. BTW: I love your Huject. Good luck! :) |
Hi @zixia, I have some concerns with the direction we're taking here. As already mentioned it's not clear how this would work for source files without running into the same performance issues we already see with Babel. The TypeScript test files won't get enhanced assertions or protection against improper I've been doing a lot of thinking on how we can better solve these problems. Not only for TypeScript but for Babel-based projects as well. I've started writing an RFC with my specific proposal but I'm not ready to share it yet. I'm currently on holiday, and the weather is awfully nice (except when there's ⛈ like right now), so I can't commit to any particular publication date. I didn't want to leave you hanging though. As I see it right now I don't think we can land this pull request. I'm really sorry about that, since you've put in a lot of work already. I hope you'll give my proposal a chance. It should enable us to make AVA's TypeScript support really awesome. Thanks. |
@novemberborn Understand, and please let me know when you made new progress on your RFC. :) Have a nice holiday! |
@novemberborn No problem, looking forward hearing from you. |
Follow #1109
Notice that this PR has to work together with avajs/ava-files#9
So unit testing in CI will expect failure before we merge&update
AvaFiles
NPM.In my development environment with
npm link ava-files
, all unit tests had passed.