-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Add support for TypeScript without precompiling #1122
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
Changes from 23 commits
30bf714
0a0e448
c3bf9b3
7ea3468
55ea370
2708e40
4024791
a925e0e
c0b276a
47b7dfc
91386f6
d7bfa76
c76199c
c9c1020
6ad050a
5629601
77f456c
e382848
5eb9ba1
685a4fe
5441111
58690ad
d91ed25
6933688
accbddb
ef26c97
aac2fc1
2ea3db7
8f2bca0
41043e7
6d071e2
d577ff5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ node_modules | |
coverage | ||
bench/.results | ||
types/generated.d.ts | ||
yarn.lock | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,7 @@ function CachingPrecompiler(options) { | |
|
||
this.babelConfig = babelConfigHelper.validate(options.babel); | ||
this.cacheDirPath = options.path; | ||
this.extensions = options.extensions || ['js']; | ||
this.powerAssert = Boolean(options.powerAssert); | ||
this.fileHashes = {}; | ||
this.transform = this._createTransform(); | ||
|
@@ -47,8 +48,33 @@ 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 commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
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 commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
|
||
var result; | ||
|
||
if (isCustomExt) { | ||
switch (fileExt) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not a fan of switch statements, simple There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @vdemedes Agreed. I usually don't use switch unless there are lots of same if's. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @zixia could you change this to an
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok. done. Now we only have one extension: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we do the following to cover both if (/^tsx?$/.test(fileExt)) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I use Could TypeScript transpile .tsx by default? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With default settings – no. But with the |
||
case 'ts': | ||
var extTs = require('./ext/ts'); | ||
result = extTs.transpile(code, filePath); | ||
break; | ||
|
||
/** | ||
* here for other extensions in the future | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment should be removed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed. |
||
*/ | ||
|
||
default: | ||
throw new Error('`--extension ' + fileExt + '` is not supported by AVA.'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's check for allowed extensions in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Had changed to 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? |
||
} | ||
} | ||
|
||
if (!result) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should just be an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
var options = babelConfigHelper.build(this.babelConfig, this.powerAssert, filePath, code); | ||
result = this.babel.transform(code, options); | ||
} | ||
|
||
// save source map | ||
var mapPath = path.join(this.cacheDirPath, hash + '.js.map'); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 Test file extension, for example `ts` for TypeScript (Can be repeated)', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think example here is extra. Or it could at least be shortened to:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shorted. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree it could be shortened, but not like that. Should be:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
'', | ||
'Examples', | ||
' ava', | ||
|
@@ -60,7 +61,8 @@ exports.run = function () { | |
'timeout', | ||
'source', | ||
'match', | ||
'concurrency' | ||
'concurrency', | ||
'extension' | ||
], | ||
boolean: [ | ||
'fail-fast', | ||
|
@@ -78,7 +80,8 @@ exports.run = function () { | |
w: 'watch', | ||
S: 'source', | ||
T: 'timeout', | ||
c: 'concurrency' | ||
c: 'concurrency', | ||
e: 'extension' | ||
} | ||
}); | ||
|
||
|
@@ -100,6 +103,8 @@ 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.'); | ||
} | ||
|
||
var extensionList = [].concat(cli.flags.extension || 'js'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I use However, I had followed your suggestion, renamed it back to |
||
|
||
var api = new Api({ | ||
failFast: cli.flags.failFast, | ||
serial: cli.flags.serial, | ||
|
@@ -112,7 +117,8 @@ exports.run = function () { | |
resolveTestsFrom: cli.input.length === 0 ? pkgDir : process.cwd(), | ||
pkgDir: pkgDir, | ||
timeout: cli.flags.timeout, | ||
concurrency: cli.flags.concurrency ? parseInt(cli.flags.concurrency, 10) : 0 | ||
concurrency: cli.flags.concurrency ? parseInt(cli.flags.concurrency, 10) : 0, | ||
extensions: extensionList | ||
}); | ||
|
||
var reporter; | ||
|
@@ -143,7 +149,7 @@ exports.run = function () { | |
|
||
if (cli.flags.watch) { | ||
try { | ||
var watcher = new Watcher(logger, api, files, arrify(cli.flags.source)); | ||
var watcher = new Watcher(logger, api, files, arrify(cli.flags.source), extensionList); | ||
watcher.observeStdin(process.stdin); | ||
} catch (err) { | ||
if (err.name === 'AvaError') { | ||
|
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
@@ -0,0 +1,111 @@ | ||||
'use strict'; | ||||
/** | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment should be removed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed. |
||||
* AVA File Extension for TypeScript | ||||
* Author: https://github.com/zixia | ||||
*/ | ||||
var fs = require('fs'); | ||||
|
||||
var typescript; | ||||
try { | ||||
typescript = require('typescript'); | ||||
} catch (err) { | ||||
console.log('AVA error: `--extensions=ts` require TypeScript to be installed.'); | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use console.error
Same with the below code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||||
throw err; | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||||
} | ||||
var tsnode; // = require('ts-node'); XXX: maybe useful in the future, because ts-node do more than typescript for our case. | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comment should be removed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. removed. |
||||
|
||||
var typescriptOptions = { | ||||
module: typescript.ModuleKind.CommonJS, | ||||
target: typescript.ScriptTarget.ES6, | ||||
sourceMap: true, | ||||
inlineSources: true, | ||||
inlineSourceMap: true | ||||
}; | ||||
|
||||
/** | ||||
* | ||||
* Ts-Node version | ||||
* | ||||
*/ | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. removed |
||||
// const originalJsHandler = require.extensions['.js'] | ||||
// const tsService = require('ts-node').register() | ||||
// const tsnodeTsHandler = require.extensions['.ts'] | ||||
// const tsnodeTsxHandler = require.extensions['.tsx'] | ||||
// delete require.extensions['.ts'] | ||||
// delete require.extensions['.tsx'] | ||||
|
||||
function tsnodeRegister() { | ||||
tsnode.register(typescriptOptions); | ||||
// if (require.extensions['.ts']) { | ||||
// throw new Error('there has already a register for `ts`') | ||||
// } | ||||
// if (!tsService) { | ||||
// throw new Error('no ts service') | ||||
// } | ||||
// require.extensions['.ts'] = tsnodeTsHandler | ||||
// require.extensions['.tsx'] = tsnodeTsxHandler | ||||
} | ||||
|
||||
function tsnodeTranspile(code, fileName) { | ||||
const tsService = require('ts-node').register(typescriptOptions); | ||||
|
||||
if (!tsService) { | ||||
throw new Error('no ts service'); | ||||
} | ||||
|
||||
const result = tsService().compile(code, fileName); | ||||
// console.log(result) | ||||
return result; | ||||
} | ||||
|
||||
/** | ||||
* | ||||
* Typescript version | ||||
* | ||||
*/ | ||||
|
||||
function typescriptRegister() { | ||||
require.extensions['.ts'] = function (module, fileName) { | ||||
var code = fs.readFileSync(fileName, 'utf8'); | ||||
var result = typescript.transpileModule(code, { | ||||
fileName, | ||||
compilerOptions: typescriptOptions, | ||||
reportDiagnostics: true | ||||
}); | ||||
// console.log('\n\n\n') | ||||
// console.log(result.outputText) | ||||
// console.log('\n\n\n') | ||||
// process.exit(0) | ||||
module._compile(result.outputText, fileName); | ||||
}; | ||||
|
||||
require('source-map-support').install({ | ||||
hookRequire: true | ||||
}); | ||||
} | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. Looks like For consistency we should not automatically transpile source files, at least until we have a better answer for the There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||||
|
||||
function typescriptTranspile(code, fileName) { | ||||
var result = typescript.transpileModule(code, { | ||||
fileName, | ||||
compilerOptions: typescriptOptions, | ||||
reportDiagnostics: true | ||||
}); | ||||
// console.log(result) | ||||
return { | ||||
code: result.outputText, | ||||
map: result.sourceMapText | ||||
}; | ||||
} | ||||
|
||||
var extTs = { | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||||
register: typescriptRegister, | ||||
transpile: typescriptTranspile, | ||||
|
||||
typescriptRegister, | ||||
typescriptTranspile, | ||||
|
||||
tsnodeRegister, | ||||
tsnodeTranspile | ||||
}; | ||||
|
||||
module.exports = extTs; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,6 +30,23 @@ process.installPrecompilerHook(); | |
const dependencies = []; | ||
process.installDependencyTracking(dependencies, testPath); | ||
|
||
if (opts.extensions) { | ||
opts.extensions.forEach(function (ext) { | ||
switch (ext) { | ||
case 'ts': | ||
var extTs = require('./ext/ts'); | ||
extTs.register(); | ||
break; | ||
case 'js': | ||
// We already have babel for ES6/7 | ||
break; | ||
|
||
default: | ||
throw new Error('`--extension ' + ext + '` is not supported by AVA.'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
} | ||
}); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe 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 This TypeScript support will only be enabled when we specify And about the dependencies, I think for TypeScript is different as for JavaScript, because:
Please correct me if I'm wrong, or missed anything. Thanks. |
||
|
||
require(testPath); // eslint-disable-line import/no-dynamic-require | ||
|
||
process.on('unhandledRejection', throwsHelper); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,10 +16,11 @@ function rethrowAsync(err) { | |
}); | ||
} | ||
|
||
function Watcher(logger, api, files, sources) { | ||
function Watcher(logger, api, files, sources, extensions) { | ||
this.debouncer = new Debouncer(this); | ||
this.avaFiles = new AvaFiles({ | ||
files: files, | ||
extensions: extensions, | ||
sources: sources | ||
}); | ||
|
||
|
@@ -59,7 +60,8 @@ function Watcher(logger, api, files, sources) { | |
|
||
var self = this; | ||
this.busy = api.run(specificFiles || files, { | ||
runOnlyExclusive: runOnlyExclusive | ||
runOnlyExclusive: runOnlyExclusive, | ||
extensions: extensions | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needs a watcher test for TypeScript. |
||
}).then(function (runStatus) { | ||
runStatus.previousFailCount = self.sumPreviousFailures(currentVector); | ||
logger.finish(runStatus); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,6 +56,29 @@ test('Without Pool: test files can be forced to run in exclusive mode', function | |
}); | ||
}); | ||
|
||
test('TypeScript default not supported', function (t) { | ||
var api = new Api(); | ||
|
||
return api.run( | ||
[path.join(__dirname, 'fixture/typescript/simple.ts')] | ||
).then(function (result) { | ||
t.fail('should not get result here: ' + result); | ||
}).catch(function (err) { | ||
t.ok('should not found ts file by default, get err: ' + err); | ||
}); | ||
}); | ||
|
||
test('TypeScript supported by set `extensions`', function (t) { | ||
var api = new Api({extensions: ['ts']}); | ||
return api.run( | ||
[path.join(__dirname, 'fixture/typescript/simple.ts')] | ||
).then(function (result) { | ||
t.is(result.testCount, 1); | ||
t.is(result.passCount, 1); | ||
t.is(result.failCount, 0); | ||
}); | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needs a test to ensure it support reading user TS config file. |
||
|
||
generateTests('With Pool: ', function (options) { | ||
options = options || {}; | ||
options.concurrency = 2; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { test } from 'ava'; | ||
|
||
test('AVA run TypeScript without tsc', t => { | ||
let i: number = 42; | ||
t.is(i, <number>42, 'meaning of life'); | ||
}); |
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.
Extra change.
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.
deleted.