Skip to content

Speed up TypeScript compilation when running test suite #416

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

Merged
merged 4 commits into from
Mar 26, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ npm-debug.log
*~
*.swp
TODO
build
13 changes: 1 addition & 12 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,17 +203,6 @@ module.exports = function(grunt) {
});
});

grunt.registerTask('init_ts_compiler', function () {
// LOL. This is because requiring ts-compiler for the first time actually
// calls fs.writeFileSync(), which when called from within a parallel
// test-runner, freaks out the file system and fails. This is pretty
// poor-form from TypeScript. The solution is to first require ts-compiler
// from this main process, before our test runner can access it, so
// fs.writeFileSync() has an opportunity to succeed.
var ts = require('ts-compiler');
});


grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-clean');
Expand All @@ -222,6 +211,6 @@ module.exports = function(grunt) {

grunt.registerTask('lint', 'Lint all source javascript', ['jshint']);
grunt.registerTask('build', 'Build distributed javascript', ['clean', 'bundle', 'copy']);
grunt.registerTask('test', 'Test built javascript', ['init_ts_compiler', 'jest']);
grunt.registerTask('test', 'Test built javascript', ['jest']);
grunt.registerTask('default', 'Lint, build and test.', ['lint', 'build', 'stats', 'test']);
}
6 changes: 4 additions & 2 deletions __tests__/flatten.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import I = require('immutable');
import jasmineCheck = require('jasmine-check');
jasmineCheck.install();

type SeqType = number | number[] | I.Iterable<number,number>;

describe('flatten', () => {

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

it('flattens only Sequences (not sequenceables)', () => {
var nested = I.Seq.of(I.Range(1,3),[3,4],I.List.of(5,6,7),8);
var nested = I.Seq.of<SeqType>(I.Range(1,3),[3,4],I.List.of(5,6,7),8);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have accepted any, but I applaud your specificity.

var flat = nested.flatten();
expect(flat.toJS()).toEqual([1,2,[3,4],5,6,7,8]);
})

it('can be reversed', () => {
var nested = I.Seq.of(I.Range(1,3),[3,4],I.List.of(5,6,7),8);
var nested = I.Seq.of<SeqType>(I.Range(1,3),[3,4],I.List.of(5,6,7),8);
var flat = nested.flatten();
var reversed = flat.reverse();
expect(reversed.toJS()).toEqual([8,7,6,5,[3,4],2,1]);
Expand Down
2 changes: 1 addition & 1 deletion __tests__/slice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ describe('slice', () => {
it('slices a sparse indexed sequence', () => {
expect(Seq([1,,2,,3,,4,,5,,6]).slice(1).toArray()).toEqual([,2,,3,,4,,5,,6]);
expect(Seq([1,,2,,3,,4,,5,,6]).slice(2).toArray()).toEqual([2,,3,,4,,5,,6]);
expect(Seq([1,,2,,3,,4,,5,,6]).slice(3, -3).toArray()).toEqual([,3,,4,,,]); // one trailing hole.
expect(Seq([1,,2,,3,,4,,5,,6]).slice(3, -3).toArray()).toEqual([,3,,4,,]); // one trailing hole.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess TypeScript changed their rules around trailing comma removal in 1.4?

})

it('can maintain indices for an keyed indexed sequence', () => {
Expand Down
4 changes: 4 additions & 0 deletions dist/immutable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,10 @@ declare module 'immutable' {
new (): Map<string, any>;
new (values: {[key: string]: any}): Map<string, any>;
new (values: Iterable<string, any>): Map<string, any>; // deprecated

(): Map<string, any>;
(values: {[key: string]: any}): Map<string, any>;
(values: Iterable<string, any>): Map<string, any>; // deprecated
}
}

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"magic-string": "^0.2.6",
"microtime": "^1.2.0",
"react-tools": "^0.11.1",
"ts-compiler": "^2.0.0",
"typescript": "^1.4.1",
"uglify-js": "^2.4.15"
},
"engines": {
Expand All @@ -71,4 +71,4 @@
"iteration"
],
"license": "BSD"
}
}
77 changes: 56 additions & 21 deletions resources/jestPreprocessor.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,66 @@
// preprocessor.js
var fs = require('fs');
var path = require('path');
var ts = require('ts-compiler');
var typescript = require('typescript');
var react = require('react-tools');

var CACHE_DIR = path.join(path.resolve(__dirname + '/../build'));

function isFileNewer(a, b) {
try {
return fs.statSync(a).mtime > fs.statSync(b).mtime;
} catch (ex) {
return false;
}
}

function compileTypeScript(filePath) {
var options = {
outDir: CACHE_DIR,
noEmitOnError: true,
target: typescript.ScriptTarget.ES5,
module: typescript.ModuleKind.CommonJS
};

// re-use cached source if possible
var outputPath = path.join(options.outDir, path.basename(filePath, '.ts')) + '.js';
if (isFileNewer(outputPath, filePath)) {
return fs.readFileSync(outputPath).toString();
}

if (fs.existsSync(outputPath)) {
fs.unlinkSync(outputPath);
}

var host = typescript.createCompilerHost(options);
var program = typescript.createProgram([filePath], options, host);
var checker = typescript.createTypeChecker(program, true /* produceDiagnostics */);
var result = checker.emitFiles();

var allErrors = program.getDiagnostics().concat(checker.getDiagnostics())
.concat(result.diagnostics);
allErrors.forEach(function(diagnostic) {
var lineChar = diagnostic.file.getLineAndCharacterFromPosition(diagnostic.start);
console.error('%s %d:%d %s', diagnostic.file.filename, lineChar.line, lineChar.character, diagnostic.messageText);
});

if (result.emitResultStatus !== typescript.EmitReturnStatus.Succeeded) {
throw new Error('Compiling ' + filePath + ' failed');
}

return fs.readFileSync(outputPath).toString();
}

module.exports = {
process: function(src, filePath) {
if (filePath.match(/\.ts$/) && !filePath.match(/\.d\.ts$/)) {
ts.compile([filePath], {
skipWrite: true,
module: 'commonjs'
}, function(err, results) {
if (err) {
throw err;
}
results.forEach(function(file) {
// This is gross, but jest doesn't provide an asynchronous way to
// process a module, and ts currently runs syncronously.
src = file.text;
});
});
return src;
}
if (filePath.match(/\.js$/)) {
return react.transform(src, {harmony: true}).replace(
/require\('immutable/g,
"require('" + path.relative(path.dirname(filePath), process.cwd())
);
return compileTypeScript(filePath);
} else if (filePath.match(/\.js$/)) {
var result = react.transform(src, {harmony: true}).replace(
/require\('immutable/g,
"require('" + path.relative(path.dirname(filePath), process.cwd())
);
return result;
}
return src;
}
Expand Down
3 changes: 0 additions & 3 deletions resources/node_test.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
#!/bin/bash

# Many lols. See gruntfile for full explanation.
node -e "require('ts-compiler')"

# Run all tests using jest
if [[ $TRAVIS ]]
then jest -i # Travis tests are run inline
Expand Down
4 changes: 4 additions & 0 deletions type-definitions/Immutable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,10 @@ declare module 'immutable' {
new (): Map<string, any>;
new (values: {[key: string]: any}): Map<string, any>;
new (values: Iterable<string, any>): Map<string, any>; // deprecated

(): Map<string, any>;
(values: {[key: string]: any}): Map<string, any>;
(values: Iterable<string, any>): Map<string, any>; // deprecated
}
}

Expand Down