Skip to content

Commit b72045e

Browse files
committed
Merge pull request immutable-js#416 from robertknight/test-perf
Speed up TypeScript compilation when running test suite
2 parents f15503f + c42586f commit b72045e

File tree

9 files changed

+73
-41
lines changed

9 files changed

+73
-41
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ npm-debug.log
66
*~
77
*.swp
88
TODO
9+
build

Gruntfile.js

+1-12
Original file line numberDiff line numberDiff line change
@@ -203,17 +203,6 @@ module.exports = function(grunt) {
203203
});
204204
});
205205

206-
grunt.registerTask('init_ts_compiler', function () {
207-
// LOL. This is because requiring ts-compiler for the first time actually
208-
// calls fs.writeFileSync(), which when called from within a parallel
209-
// test-runner, freaks out the file system and fails. This is pretty
210-
// poor-form from TypeScript. The solution is to first require ts-compiler
211-
// from this main process, before our test runner can access it, so
212-
// fs.writeFileSync() has an opportunity to succeed.
213-
var ts = require('ts-compiler');
214-
});
215-
216-
217206
grunt.loadNpmTasks('grunt-contrib-jshint');
218207
grunt.loadNpmTasks('grunt-contrib-copy');
219208
grunt.loadNpmTasks('grunt-contrib-clean');
@@ -222,6 +211,6 @@ module.exports = function(grunt) {
222211

223212
grunt.registerTask('lint', 'Lint all source javascript', ['jshint']);
224213
grunt.registerTask('build', 'Build distributed javascript', ['clean', 'bundle', 'copy']);
225-
grunt.registerTask('test', 'Test built javascript', ['init_ts_compiler', 'jest']);
214+
grunt.registerTask('test', 'Test built javascript', ['jest']);
226215
grunt.registerTask('default', 'Lint, build and test.', ['lint', 'build', 'stats', 'test']);
227216
}

__tests__/flatten.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import I = require('immutable');
88
import jasmineCheck = require('jasmine-check');
99
jasmineCheck.install();
1010

11+
type SeqType = number | number[] | I.Iterable<number,number>;
12+
1113
describe('flatten', () => {
1214

1315
it('flattens sequences one level deep', () => {
@@ -29,13 +31,13 @@ describe('flatten', () => {
2931
})
3032

3133
it('flattens only Sequences (not sequenceables)', () => {
32-
var nested = I.Seq.of(I.Range(1,3),[3,4],I.List.of(5,6,7),8);
34+
var nested = I.Seq.of<SeqType>(I.Range(1,3),[3,4],I.List.of(5,6,7),8);
3335
var flat = nested.flatten();
3436
expect(flat.toJS()).toEqual([1,2,[3,4],5,6,7,8]);
3537
})
3638

3739
it('can be reversed', () => {
38-
var nested = I.Seq.of(I.Range(1,3),[3,4],I.List.of(5,6,7),8);
40+
var nested = I.Seq.of<SeqType>(I.Range(1,3),[3,4],I.List.of(5,6,7),8);
3941
var flat = nested.flatten();
4042
var reversed = flat.reverse();
4143
expect(reversed.toJS()).toEqual([8,7,6,5,[3,4],2,1]);

__tests__/slice.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ describe('slice', () => {
3131
it('slices a sparse indexed sequence', () => {
3232
expect(Seq([1,,2,,3,,4,,5,,6]).slice(1).toArray()).toEqual([,2,,3,,4,,5,,6]);
3333
expect(Seq([1,,2,,3,,4,,5,,6]).slice(2).toArray()).toEqual([2,,3,,4,,5,,6]);
34-
expect(Seq([1,,2,,3,,4,,5,,6]).slice(3, -3).toArray()).toEqual([,3,,4,,,]); // one trailing hole.
34+
expect(Seq([1,,2,,3,,4,,5,,6]).slice(3, -3).toArray()).toEqual([,3,,4,,]); // one trailing hole.
3535
})
3636

3737
it('can maintain indices for an keyed indexed sequence', () => {

dist/immutable.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,10 @@ declare module 'immutable' {
10671067
new (): Map<string, any>;
10681068
new (values: {[key: string]: any}): Map<string, any>;
10691069
new (values: Iterable<string, any>): Map<string, any>; // deprecated
1070+
1071+
(): Map<string, any>;
1072+
(values: {[key: string]: any}): Map<string, any>;
1073+
(values: Iterable<string, any>): Map<string, any>; // deprecated
10701074
}
10711075
}
10721076

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"magic-string": "^0.2.6",
4646
"microtime": "^1.2.0",
4747
"react-tools": "^0.11.1",
48-
"ts-compiler": "^2.0.0",
48+
"typescript": "^1.4.1",
4949
"uglify-js": "^2.4.15"
5050
},
5151
"engines": {
@@ -71,4 +71,4 @@
7171
"iteration"
7272
],
7373
"license": "BSD"
74-
}
74+
}

resources/jestPreprocessor.js

+56-21
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,66 @@
11
// preprocessor.js
2+
var fs = require('fs');
23
var path = require('path');
3-
var ts = require('ts-compiler');
4+
var typescript = require('typescript');
45
var react = require('react-tools');
56

7+
var CACHE_DIR = path.join(path.resolve(__dirname + '/../build'));
8+
9+
function isFileNewer(a, b) {
10+
try {
11+
return fs.statSync(a).mtime > fs.statSync(b).mtime;
12+
} catch (ex) {
13+
return false;
14+
}
15+
}
16+
17+
function compileTypeScript(filePath) {
18+
var options = {
19+
outDir: CACHE_DIR,
20+
noEmitOnError: true,
21+
target: typescript.ScriptTarget.ES5,
22+
module: typescript.ModuleKind.CommonJS
23+
};
24+
25+
// re-use cached source if possible
26+
var outputPath = path.join(options.outDir, path.basename(filePath, '.ts')) + '.js';
27+
if (isFileNewer(outputPath, filePath)) {
28+
return fs.readFileSync(outputPath).toString();
29+
}
30+
31+
if (fs.existsSync(outputPath)) {
32+
fs.unlinkSync(outputPath);
33+
}
34+
35+
var host = typescript.createCompilerHost(options);
36+
var program = typescript.createProgram([filePath], options, host);
37+
var checker = typescript.createTypeChecker(program, true /* produceDiagnostics */);
38+
var result = checker.emitFiles();
39+
40+
var allErrors = program.getDiagnostics().concat(checker.getDiagnostics())
41+
.concat(result.diagnostics);
42+
allErrors.forEach(function(diagnostic) {
43+
var lineChar = diagnostic.file.getLineAndCharacterFromPosition(diagnostic.start);
44+
console.error('%s %d:%d %s', diagnostic.file.filename, lineChar.line, lineChar.character, diagnostic.messageText);
45+
});
46+
47+
if (result.emitResultStatus !== typescript.EmitReturnStatus.Succeeded) {
48+
throw new Error('Compiling ' + filePath + ' failed');
49+
}
50+
51+
return fs.readFileSync(outputPath).toString();
52+
}
53+
654
module.exports = {
755
process: function(src, filePath) {
856
if (filePath.match(/\.ts$/) && !filePath.match(/\.d\.ts$/)) {
9-
ts.compile([filePath], {
10-
skipWrite: true,
11-
module: 'commonjs'
12-
}, function(err, results) {
13-
if (err) {
14-
throw err;
15-
}
16-
results.forEach(function(file) {
17-
// This is gross, but jest doesn't provide an asynchronous way to
18-
// process a module, and ts currently runs syncronously.
19-
src = file.text;
20-
});
21-
});
22-
return src;
23-
}
24-
if (filePath.match(/\.js$/)) {
25-
return react.transform(src, {harmony: true}).replace(
26-
/require\('immutable/g,
27-
"require('" + path.relative(path.dirname(filePath), process.cwd())
28-
);
57+
return compileTypeScript(filePath);
58+
} else if (filePath.match(/\.js$/)) {
59+
var result = react.transform(src, {harmony: true}).replace(
60+
/require\('immutable/g,
61+
"require('" + path.relative(path.dirname(filePath), process.cwd())
62+
);
63+
return result;
2964
}
3065
return src;
3166
}

resources/node_test.sh

-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
#!/bin/bash
22

3-
# Many lols. See gruntfile for full explanation.
4-
node -e "require('ts-compiler')"
5-
63
# Run all tests using jest
74
if [[ $TRAVIS ]]
85
then jest -i # Travis tests are run inline

type-definitions/Immutable.d.ts

+4
Original file line numberDiff line numberDiff line change
@@ -1067,6 +1067,10 @@ declare module 'immutable' {
10671067
new (): Map<string, any>;
10681068
new (values: {[key: string]: any}): Map<string, any>;
10691069
new (values: Iterable<string, any>): Map<string, any>; // deprecated
1070+
1071+
(): Map<string, any>;
1072+
(values: {[key: string]: any}): Map<string, any>;
1073+
(values: Iterable<string, any>): Map<string, any>; // deprecated
10701074
}
10711075
}
10721076

0 commit comments

Comments
 (0)