UNPKG

typescript-closure-tools

Version:

Command-line tools to convert closure-style JSDoc annotations to typescript, and to convert typescript sources to closure externs files

1,322 lines (1,155 loc) 47.9 kB
var DT; (function (DT) { 'use strict'; var Promise = require('bluebird'); var nodeExec = require('child_process').exec; var ExecResult = (function () { function ExecResult() { this.stdout = ''; this.stderr = ''; } return ExecResult; })(); DT.ExecResult = ExecResult; function exec(filename, cmdLineArgs) { return new Promise(function (resolve) { var result = new ExecResult(); result.exitCode = null; var cmdLine = filename + ' ' + cmdLineArgs.join(' '); nodeExec(cmdLine, { maxBuffer: 1 * 1024 * 1024 }, function (error, stdout, stderr) { result.error = error; result.stdout = stdout; result.stderr = stderr; result.exitCode = error ? error.code : 0; resolve(result); }); }); } DT.exec = exec; })(DT || (DT = {})); /// <reference path="../_ref.d.ts" /> var DT; (function (DT) { 'use strict'; var path = require('path'); ///////////////////////////////// // Given a document root + ts file pattern this class returns: // all the TS files OR just tests OR just definition files ///////////////////////////////// var File = (function () { function File(baseDir, filePathWithName) { this.references = []; // why choose? this.baseDir = baseDir; this.filePathWithName = filePathWithName; this.ext = path.extname(this.filePathWithName); this.file = path.basename(this.filePathWithName, this.ext); this.dir = path.dirname(this.filePathWithName); this.fullPath = path.join(this.baseDir, this.dir, this.file + this.ext); // lock it (shallow) (needs `use strict` in each file to work) // Object.freeze(this); } File.prototype.toString = function () { return '[File ' + this.filePathWithName + ']'; }; return File; })(); DT.File = File; })(DT || (DT = {})); /// <reference path='../_ref.d.ts' /> /// <reference path='../runner.ts' /> /// <reference path='exec.ts' /> var DT; (function (DT) { 'use strict'; var fs = require('fs'); var Promise = require('bluebird'); var Tsc = (function () { function Tsc() { } Tsc.run = function (tsfile, options) { var tscPath; return new Promise.attempt(function () { options = options || {}; options.tscVersion = options.tscVersion || DT.DEFAULT_TSC_VERSION; if (typeof options.checkNoImplicitAny === 'undefined') { options.checkNoImplicitAny = true; } if (typeof options.useTscParams === 'undefined') { options.useTscParams = true; } return DT.fileExists(tsfile); }).then(function (exists) { if (!exists) { throw new Error(tsfile + ' not exists'); } tscPath = './_infrastructure/tests/typescript/' + options.tscVersion + '/tsc.js'; return DT.fileExists(tscPath); }).then(function (exists) { if (!exists) { throw new Error(tscPath + ' is not exists'); } return DT.fileExists(tsfile + '.tscparams'); }).then(function (exists) { var command = 'node ' + tscPath + ' --module commonjs '; if (options.useTscParams && exists) { command += '@' + tsfile + '.tscparams'; } else if (options.checkNoImplicitAny) { command += '--noImplicitAny'; } return DT.exec(command, [tsfile]); }); }; return Tsc; })(); DT.Tsc = Tsc; })(DT || (DT = {})); /// <reference path="../_ref.d.ts" /> /// <reference path="../runner.ts" /> var DT; (function (DT) { 'use strict'; ///////////////////////////////// // Timer.start starts a timer // Timer.end stops the timer and sets asString to the pretty print value ///////////////////////////////// var Timer = (function () { function Timer() { this.time = 0; this.asString = '<not-started>'; } Timer.prototype.start = function () { this.time = 0; this.startTime = this.now(); this.asString = '<started>'; }; Timer.prototype.now = function () { return Date.now(); }; Timer.prototype.end = function () { this.time = (this.now() - this.startTime) / 1000; this.asString = Timer.prettyDate(this.startTime, this.now()); }; Timer.prettyDate = function (date1, date2) { var diff = ((date2 - date1) / 1000); var day_diff = Math.floor(diff / 86400); if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31) { return null; } return (day_diff == 0 && (diff < 60 && (diff + ' seconds') || diff < 120 && '1 minute' || diff < 3600 && Math.floor(diff / 60) + ' minutes' || diff < 7200 && '1 hour' || diff < 86400 && Math.floor(diff / 3600) + ' hours') || day_diff == 1 && 'Yesterday' || day_diff < 7 && day_diff + ' days' || day_diff < 31 && Math.ceil(day_diff / 7) + ' weeks'); }; return Timer; })(); DT.Timer = Timer; })(DT || (DT = {})); /// <reference path="../_ref.d.ts" /> var DT; (function (DT) { 'use strict'; var fs = require('fs'); var Lazy = require('lazy.js'); var Promise = require('bluebird'); var referenceTagExp = /<reference[ \t]*path=["']?([\w\.\/_-]*)["']?[ \t]*\/>/g; function endsWith(str, suffix) { return str.indexOf(suffix, str.length - suffix.length) !== -1; } DT.endsWith = endsWith; function extractReferenceTags(source) { var ret = []; var match; if (!referenceTagExp.global) { throw new Error('referenceTagExp RegExp must have global flag'); } referenceTagExp.lastIndex = 0; while ((match = referenceTagExp.exec(source))) { if (match.length > 0 && match[1].length > 0) { ret.push(match[1]); } } return ret; } DT.extractReferenceTags = extractReferenceTags; function fileExists(target) { return new Promise(function (resolve, reject) { fs.exists(target, function (bool) { resolve(bool); }); }); } DT.fileExists = fileExists; })(DT || (DT = {})); /// <reference path="../_ref.d.ts" /> /// <reference path="../runner.ts" /> /// <reference path="util.ts" /> var DT; (function (DT) { 'use strict'; var fs = require('fs'); var path = require('path'); var glob = require('glob'); var Lazy = require('lazy.js'); var Promise = require('bluebird'); var readFile = Promise.promisify(fs.readFile); ///////////////////////////////// // Track all files in the repo: map full path to File objects ///////////////////////////////// var FileIndex = (function () { function FileIndex(runner, options) { this.runner = runner; this.options = options; } FileIndex.prototype.hasFile = function (target) { return target in this.fileMap; }; FileIndex.prototype.getFile = function (target) { if (target in this.fileMap) { return this.fileMap[target]; } return null; }; FileIndex.prototype.setFile = function (file) { if (file.fullPath in this.fileMap) { throw new Error('cannot overwrite file'); } this.fileMap[file.fullPath] = file; }; FileIndex.prototype.readIndex = function () { var _this = this; this.fileMap = Object.create(null); return Promise.promisify(glob).call(glob, '**/*.ts', { cwd: this.runner.dtPath }).then(function (filesNames) { _this.files = Lazy(filesNames).filter(function (fileName) { return _this.runner.checkAcceptFile(fileName); }).map(function (fileName) { var file = new DT.File(_this.runner.dtPath, fileName); _this.fileMap[file.fullPath] = file; return file; }).toArray(); }); }; FileIndex.prototype.collectDiff = function (changes) { var _this = this; return new Promise(function (resolve) { // filter changes and bake map for easy lookup _this.changed = Object.create(null); _this.removed = Object.create(null); Lazy(changes).filter(function (full) { return _this.runner.checkAcceptFile(full); }).uniq().each(function (local) { var full = path.resolve(_this.runner.dtPath, local); var file = _this.getFile(full); if (!file) { // TODO figure out what to do here // what does it mean? deleted?ss file = new DT.File(_this.runner.dtPath, local); _this.setFile(file); _this.removed[full] = file; // console.log('not in index? %', file.fullPath); } else { _this.changed[full] = file; } }); // console.log('changed:\n' + Object.keys(this.changed).join('\n')); // console.log('removed:\n' + Object.keys(this.removed).join('\n')); resolve(); }); }; FileIndex.prototype.parseFiles = function () { var _this = this; return this.loadReferences(this.files).then(function () { return _this.getMissingReferences(); }); }; FileIndex.prototype.getMissingReferences = function () { var _this = this; return Promise.attempt(function () { _this.missing = Object.create(null); Lazy(_this.removed).keys().each(function (removed) { if (removed in _this.refMap) { _this.missing[removed] = _this.refMap[removed]; } }); }); }; FileIndex.prototype.loadReferences = function (files) { var _this = this; return new Promise(function (resolve, reject) { var queue = files.slice(0); var active = []; var max = 50; var next = function () { if (queue.length === 0 && active.length === 0) { resolve(); return; } while (queue.length > 0 && active.length < max) { var file = queue.pop(); active.push(file); _this.parseFile(file).then(function (file) { active.splice(active.indexOf(file), 1); next(); }).catch(function (err) { queue = []; active = []; reject(err); }); } }; next(); }).then(function () { // bake reverse reference map (referenced to referrers) _this.refMap = Object.create(null); Lazy(files).each(function (file) { Lazy(file.references).each(function (ref) { if (ref.fullPath in _this.refMap) { _this.refMap[ref.fullPath].push(file); } else { _this.refMap[ref.fullPath] = [file]; } }); }); }); }; // TODO replace with a stream? FileIndex.prototype.parseFile = function (file) { var _this = this; return readFile(file.filePathWithName, { encoding: 'utf8', flag: 'r' }).then(function (content) { file.references = Lazy(DT.extractReferenceTags(content)).map(function (ref) { return path.resolve(path.dirname(file.fullPath), ref); }).reduce(function (memo, ref) { if (ref in _this.fileMap) { memo.push(_this.fileMap[ref]); } else { console.log('not mapped? -> ' + ref); } return memo; }, []); // return the object return file; }); }; FileIndex.prototype.collectTargets = function () { var _this = this; return new Promise(function (resolve) { // map out files linked to changes // - queue holds files touched by a change // - pre-fill with actually changed files // - loop queue, if current not seen: // - add to result // - from refMap queue all files referring to current var result = Object.create(null); var queue = Lazy(_this.changed).values().toArray(); while (queue.length > 0) { var next = queue.shift(); var fp = next.fullPath; if (result[fp]) { continue; } result[fp] = next; if (fp in _this.refMap) { var arr = _this.refMap[fp]; for (var i = 0, ii = arr.length; i < ii; i++) { // just add it and skip expensive checks queue.push(arr[i]); } } } resolve(Lazy(result).values().toArray()); }); }; return FileIndex; })(); DT.FileIndex = FileIndex; })(DT || (DT = {})); /// <reference path="../_ref.d.ts" /> /// <reference path="../runner.ts" /> var DT; (function (DT) { 'use strict'; var fs = require('fs'); var path = require('path'); var Git = require('git-wrapper'); var Promise = require('bluebird'); var GitChanges = (function () { function GitChanges(runner) { this.runner = runner; this.options = {}; var dir = path.join(this.runner.dtPath, '.git'); if (!fs.existsSync(dir)) { throw new Error('cannot locate git-dir: ' + dir); } this.options['git-dir'] = dir; this.git = new Git(this.options); this.git.exec = Promise.promisify(this.git.exec); } GitChanges.prototype.readChanges = function () { var opts = {}; var args = ['--name-only HEAD~1']; return this.git.exec('diff', opts, args).then(function (msg) { return msg.replace(/^\s+/, '').replace(/\s+$/, '').split(/\r?\n/g); }); }; return GitChanges; })(); DT.GitChanges = GitChanges; })(DT || (DT = {})); /// <reference path="../_ref.d.ts" /> /// <reference path="../runner.ts" /> var DT; (function (DT) { var os = require('os'); ///////////////////////////////// // All the common things that we print are functions of this class ///////////////////////////////// var Print = (function () { function Print(version) { this.version = version; this.WIDTH = 77; } Print.prototype.init = function (typings, tests, tsFiles) { this.typings = typings; this.tests = tests; this.tsFiles = tsFiles; }; Print.prototype.out = function (s) { process.stdout.write(s); return this; }; Print.prototype.repeat = function (s, times) { return new Array(times + 1).join(s); }; Print.prototype.printChangeHeader = function () { this.out('=============================================================================\n'); this.out(' \33[36m\33[1mDefinitelyTyped Diff Detector 0.1.0\33[0m \n'); this.out('=============================================================================\n'); }; Print.prototype.printHeader = function (options) { var totalMem = Math.round(os.totalmem() / 1024 / 1024) + ' mb'; var freemem = Math.round(os.freemem() / 1024 / 1024) + ' mb'; this.out('=============================================================================\n'); this.out(' \33[36m\33[1mDefinitelyTyped Test Runner 0.5.0\33[0m\n'); this.out('=============================================================================\n'); this.out(' \33[36m\33[1mTypescript version:\33[0m ' + this.version + '\n'); this.out(' \33[36m\33[1mTypings :\33[0m ' + this.typings + '\n'); this.out(' \33[36m\33[1mTests :\33[0m ' + this.tests + '\n'); this.out(' \33[36m\33[1mTypeScript files :\33[0m ' + this.tsFiles + '\n'); this.out(' \33[36m\33[1mTotal Memory :\33[0m ' + totalMem + '\n'); this.out(' \33[36m\33[1mFree Memory :\33[0m ' + freemem + '\n'); this.out(' \33[36m\33[1mCores :\33[0m ' + os.cpus().length + '\n'); this.out(' \33[36m\33[1mConcurrent :\33[0m ' + options.concurrent + '\n'); }; Print.prototype.printSuiteHeader = function (title) { var left = Math.floor((this.WIDTH - title.length) / 2) - 1; var right = Math.ceil((this.WIDTH - title.length) / 2) - 1; this.out(this.repeat('=', left)).out(' \33[34m\33[1m'); this.out(title); this.out('\33[0m ').out(this.repeat('=', right)).printBreak(); }; Print.prototype.printDiv = function () { this.out('-----------------------------------------------------------------------------\n'); }; Print.prototype.printBoldDiv = function () { this.out('=============================================================================\n'); }; Print.prototype.printErrorsHeader = function () { this.out('=============================================================================\n'); this.out(' \33[34m\33[1mErrors in files\33[0m \n'); this.out('=============================================================================\n'); }; Print.prototype.printErrorsForFile = function (testResult) { this.out('----------------- For file:' + testResult.targetFile.filePathWithName); this.printBreak().out(testResult.stderr).printBreak(); }; Print.prototype.printBreak = function () { this.out('\n'); return this; }; Print.prototype.clearCurrentLine = function () { this.out('\r\33[K'); return this; }; Print.prototype.printSuccessCount = function (current, total) { var arb = (total === 0) ? 0 : (current / total); this.out(' \33[36m\33[1mSuccessful :\33[0m \33[32m\33[1m' + (arb * 100).toFixed(2) + '% (' + current + '/' + total + ')\33[0m\n'); }; Print.prototype.printFailedCount = function (current, total) { var arb = (total === 0) ? 0 : (current / total); this.out(' \33[36m\33[1mFailure :\33[0m \33[31m\33[1m' + (arb * 100).toFixed(2) + '% (' + current + '/' + total + ')\33[0m\n'); }; Print.prototype.printTypingsWithoutTestsMessage = function () { this.out(' \33[36m\33[1mTyping without tests\33[0m\n'); }; Print.prototype.printTotalMessage = function () { this.out(' \33[36m\33[1mTotal\33[0m\n'); }; Print.prototype.printElapsedTime = function (time, s) { this.out(' \33[36m\33[1mElapsed time :\33[0m ~' + time + ' (' + s + 's)\n'); }; Print.prototype.printSuiteErrorCount = function (errorHeadline, current, total, warn) { if (typeof warn === "undefined") { warn = false; } var arb = (total === 0) ? 0 : (current / total); this.out(' \33[36m\33[1m').out(errorHeadline).out(this.repeat(' ', 16 - errorHeadline.length)); if (warn) { this.out(': \33[31m\33[1m' + (arb * 100).toFixed(2) + '% (' + current + '/' + total + ')\33[0m\n'); } else { this.out(': \33[33m\33[1m' + (arb * 100).toFixed(2) + '% (' + current + '/' + total + ')\33[0m\n'); } }; Print.prototype.printSubHeader = function (file) { this.out(' \33[36m\33[1m' + file + '\33[0m\n'); }; Print.prototype.printWarnCode = function (str) { this.out(' \33[31m\33[1m<' + str.toLowerCase().replace(/ +/g, '-') + '>\33[0m\n'); }; Print.prototype.printLine = function (file) { this.out(file + '\n'); }; Print.prototype.printElement = function (file) { this.out(' - ' + file + '\n'); }; Print.prototype.printElement2 = function (file) { this.out(' - ' + file + '\n'); }; Print.prototype.printTypingsWithoutTestName = function (file) { this.out(' - \33[33m\33[1m' + file + '\33[0m\n'); }; Print.prototype.printTypingsWithoutTest = function (withoutTestTypings) { var _this = this; if (withoutTestTypings.length > 0) { this.printTypingsWithoutTestsMessage(); this.printDiv(); withoutTestTypings.forEach(function (t) { _this.printTypingsWithoutTestName(t); }); } }; Print.prototype.printTestComplete = function (testResult) { var reporter = testResult.hostedBy.testReporter; if (testResult.success) { reporter.printPositiveCharacter(testResult); } else { reporter.printNegativeCharacter(testResult); } }; Print.prototype.printSuiteComplete = function (suite) { this.printBreak(); this.printDiv(); this.printElapsedTime(suite.timer.asString, suite.timer.time); this.printSuccessCount(suite.okTests.length, suite.testResults.length); this.printFailedCount(suite.ngTests.length, suite.testResults.length); }; Print.prototype.printTests = function (adding) { var _this = this; this.printDiv(); this.printSubHeader('Testing'); this.printDiv(); Object.keys(adding).sort().map(function (src) { _this.printLine(adding[src].filePathWithName); return adding[src]; }); }; Print.prototype.printQueue = function (files) { var _this = this; this.printDiv(); this.printSubHeader('Queued for testing'); this.printDiv(); files.forEach(function (file) { _this.printLine(file.filePathWithName); }); }; Print.prototype.printTestAll = function () { this.printDiv(); this.printSubHeader('Ignoring changes, testing all files'); }; Print.prototype.printFiles = function (files) { var _this = this; this.printDiv(); this.printSubHeader('Files'); this.printDiv(); files.forEach(function (file) { _this.printLine(file.filePathWithName); file.references.forEach(function (file) { _this.printElement(file.filePathWithName); }); }); }; Print.prototype.printMissing = function (index, refMap) { var _this = this; this.printDiv(); this.printSubHeader('Missing references'); this.printDiv(); Object.keys(refMap).sort().forEach(function (src) { var ref = index.getFile(src); _this.printLine('\33[31m\33[1m' + ref.filePathWithName + '\33[0m'); refMap[src].forEach(function (file) { _this.printElement(file.filePathWithName); }); }); }; Print.prototype.printAllChanges = function (paths) { var _this = this; this.printSubHeader('All changes'); this.printDiv(); paths.sort().forEach(function (line) { _this.printLine(line); }); }; Print.prototype.printRelChanges = function (changeMap) { var _this = this; this.printDiv(); this.printSubHeader('Interesting files'); this.printDiv(); Object.keys(changeMap).sort().forEach(function (src) { _this.printLine(changeMap[src].filePathWithName); }); }; Print.prototype.printRemovals = function (changeMap) { var _this = this; this.printDiv(); this.printSubHeader('Removed files'); this.printDiv(); Object.keys(changeMap).sort().forEach(function (src) { _this.printLine(changeMap[src].filePathWithName); }); }; Print.prototype.printRefMap = function (index, refMap) { var _this = this; this.printDiv(); this.printSubHeader('Referring'); this.printDiv(); Object.keys(refMap).sort().forEach(function (src) { var ref = index.getFile(src); _this.printLine(ref.filePathWithName); refMap[src].forEach(function (file) { _this.printLine(' - ' + file.filePathWithName); }); }); }; return Print; })(); DT.Print = Print; })(DT || (DT = {})); /// <reference path="../../_ref.d.ts" /> /// <reference path="../printer.ts" /> var DT; (function (DT) { ///////////////////////////////// // Default test reporter ///////////////////////////////// var DefaultTestReporter = (function () { function DefaultTestReporter(print) { this.print = print; this.index = 0; } DefaultTestReporter.prototype.printPositiveCharacter = function (testResult) { this.print.out('\33[36m\33[1m' + '.' + '\33[0m'); this.index++; this.printBreakIfNeeded(this.index); }; DefaultTestReporter.prototype.printNegativeCharacter = function (testResult) { this.print.out('x'); this.index++; this.printBreakIfNeeded(this.index); }; DefaultTestReporter.prototype.printBreakIfNeeded = function (index) { if (index % this.print.WIDTH === 0) { this.print.printBreak(); } }; return DefaultTestReporter; })(); DT.DefaultTestReporter = DefaultTestReporter; })(DT || (DT = {})); /// <reference path="../../runner.ts" /> var DT; (function (DT) { 'use strict'; var Promise = require('bluebird'); ///////////////////////////////// // Base class for test suite ///////////////////////////////// var TestSuiteBase = (function () { function TestSuiteBase(options, testSuiteName, errorHeadline) { this.options = options; this.testSuiteName = testSuiteName; this.errorHeadline = errorHeadline; this.timer = new DT.Timer(); this.testResults = []; this.printErrorCount = true; this.queue = new DT.TestQueue(options.concurrent); } TestSuiteBase.prototype.filterTargetFiles = function (files) { throw new Error('please implement this method'); }; TestSuiteBase.prototype.start = function (targetFiles, testCallback) { var _this = this; this.timer.start(); return this.filterTargetFiles(targetFiles).then(function (targetFiles) { // tests get queued for multi-threading return Promise.all(targetFiles.map(function (targetFile) { return _this.runTest(targetFile).then(function (result) { testCallback(result); }); })); }).then(function () { _this.timer.end(); return _this; }); }; TestSuiteBase.prototype.runTest = function (targetFile) { var _this = this; return this.queue.run(new DT.Test(this, targetFile, { tscVersion: this.options.tscVersion })).then(function (result) { _this.testResults.push(result); return result; }); }; Object.defineProperty(TestSuiteBase.prototype, "okTests", { get: function () { return this.testResults.filter(function (r) { return r.success; }); }, enumerable: true, configurable: true }); Object.defineProperty(TestSuiteBase.prototype, "ngTests", { get: function () { return this.testResults.filter(function (r) { return !r.success; }); }, enumerable: true, configurable: true }); return TestSuiteBase; })(); DT.TestSuiteBase = TestSuiteBase; })(DT || (DT = {})); /// <reference path="../../runner.ts" /> /// <reference path="../util.ts" /> var __extends = this.__extends || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } __.prototype = b.prototype; d.prototype = new __(); }; var DT; (function (DT) { 'use strict'; var Promise = require('bluebird'); var endDts = /\w\.d\.ts$/i; ///////////////////////////////// // .d.ts syntax inspection ///////////////////////////////// var SyntaxChecking = (function (_super) { __extends(SyntaxChecking, _super); function SyntaxChecking(options) { _super.call(this, options, 'Syntax checking', 'Syntax error'); } SyntaxChecking.prototype.filterTargetFiles = function (files) { return Promise.cast(files.filter(function (file) { return endDts.test(file.filePathWithName); })); }; return SyntaxChecking; })(DT.TestSuiteBase); DT.SyntaxChecking = SyntaxChecking; })(DT || (DT = {})); /// <reference path="../../runner.ts" /> /// <reference path="../util.ts" /> var DT; (function (DT) { 'use strict'; var Promise = require('bluebird'); var endTestDts = /\w-tests?\.ts$/i; ///////////////////////////////// // Compile with *-tests.ts ///////////////////////////////// var TestEval = (function (_super) { __extends(TestEval, _super); function TestEval(options) { _super.call(this, options, 'Typing tests', 'Failed tests'); } TestEval.prototype.filterTargetFiles = function (files) { return Promise.cast(files.filter(function (file) { return endTestDts.test(file.filePathWithName); })); }; return TestEval; })(DT.TestSuiteBase); DT.TestEval = TestEval; })(DT || (DT = {})); /// <reference path='../../runner.ts' /> /// <reference path='../file.ts' /> var DT; (function (DT) { 'use strict'; var fs = require('fs'); var Promise = require('bluebird'); ///////////////////////////////// // Try compile without .tscparams // It may indicate that it is compatible with --noImplicitAny maybe... ///////////////////////////////// var FindNotRequiredTscparams = (function (_super) { __extends(FindNotRequiredTscparams, _super); function FindNotRequiredTscparams(options, print) { var _this = this; _super.call(this, options, 'Find not required .tscparams files', 'New arrival!'); this.print = print; this.printErrorCount = false; this.testReporter = { printPositiveCharacter: function (testResult) { _this.print.clearCurrentLine().printTypingsWithoutTestName(testResult.targetFile.filePathWithName); }, printNegativeCharacter: function (testResult) { } }; } FindNotRequiredTscparams.prototype.filterTargetFiles = function (files) { return Promise.filter(files, function (file) { return new Promise(function (resolve) { fs.exists(file.filePathWithName + '.tscparams', resolve); }); }); }; FindNotRequiredTscparams.prototype.runTest = function (targetFile) { var _this = this; this.print.clearCurrentLine().out(targetFile.filePathWithName); return this.queue.run(new DT.Test(this, targetFile, { tscVersion: this.options.tscVersion, useTscParams: false, checkNoImplicitAny: true })).then(function (result) { _this.testResults.push(result); _this.print.clearCurrentLine(); return result; }); }; Object.defineProperty(FindNotRequiredTscparams.prototype, "ngTests", { get: function () { // Do not show ng test results return []; }, enumerable: true, configurable: true }); return FindNotRequiredTscparams; })(DT.TestSuiteBase); DT.FindNotRequiredTscparams = FindNotRequiredTscparams; })(DT || (DT = {})); /// <reference path="typings/tsd.d.ts" /> /// <reference path="src/exec.ts" /> /// <reference path="src/file.ts" /> /// <reference path="src/tsc.ts" /> /// <reference path="src/timer.ts" /> /// <reference path="src/util.ts" /> /// <reference path="src/index.ts" /> /// <reference path="src/changes.ts" /> /// <reference path="src/printer.ts" /> /// <reference path="src/reporter/reporter.ts" /> /// <reference path="src/suite/suite.ts" /> /// <reference path="src/suite/syntax.ts" /> /// <reference path="src/suite/testEval.ts" /> /// <reference path="src/suite/tscParams.ts" /> var DT; (function (DT) { require('source-map-support').install(); // hacky typing var Lazy = require('lazy.js'); var Promise = require('bluebird'); var os = require('os'); var fs = require('fs'); var path = require('path'); var assert = require('assert'); var tsExp = /\.ts$/; DT.DEFAULT_TSC_VERSION = '0.9.7'; ///////////////////////////////// // Single test ///////////////////////////////// var Test = (function () { function Test(suite, tsfile, options) { this.suite = suite; this.tsfile = tsfile; this.options = options; } Test.prototype.run = function () { var _this = this; return DT.Tsc.run(this.tsfile.filePathWithName, this.options).then(function (execResult) { var testResult = new TestResult(); testResult.hostedBy = _this.suite; testResult.targetFile = _this.tsfile; testResult.options = _this.options; testResult.stdout = execResult.stdout; testResult.stderr = execResult.stderr; testResult.exitCode = execResult.exitCode; return testResult; }); }; return Test; })(); DT.Test = Test; ///////////////////////////////// // Parallel execute Tests ///////////////////////////////// var TestQueue = (function () { function TestQueue(concurrent) { this.queue = []; this.active = []; this.concurrent = Math.max(1, concurrent); } // add to queue and return a promise TestQueue.prototype.run = function (test) { var _this = this; var defer = Promise.defer(); // add a closure to queue this.queue.push(function () { // run it var p = test.run(); p.then(defer.resolve.bind(defer), defer.reject.bind(defer)); p.finally(function () { var i = _this.active.indexOf(test); if (i > -1) { _this.active.splice(i, 1); } _this.step(); }); // return it return test; }); this.step(); // defer it return defer.promise; }; TestQueue.prototype.step = function () { while (this.queue.length > 0 && this.active.length < this.concurrent) { this.active.push(this.queue.pop().call(null)); } }; return TestQueue; })(); DT.TestQueue = TestQueue; ///////////////////////////////// // Test results ///////////////////////////////// var TestResult = (function () { function TestResult() { } Object.defineProperty(TestResult.prototype, "success", { get: function () { return this.exitCode === 0; }, enumerable: true, configurable: true }); return TestResult; })(); DT.TestResult = TestResult; ///////////////////////////////// // The main class to kick things off ///////////////////////////////// var TestRunner = (function () { function TestRunner(dtPath, options) { if (typeof options === "undefined") { options = { tscVersion: DT.DEFAULT_TSC_VERSION }; } this.dtPath = dtPath; this.options = options; this.suites = []; this.options.findNotRequiredTscparams = !!this.options.findNotRequiredTscparams; this.index = new DT.FileIndex(this, this.options); this.changes = new DT.GitChanges(this); this.print = new DT.Print(this.options.tscVersion); } TestRunner.prototype.addSuite = function (suite) { this.suites.push(suite); }; TestRunner.prototype.checkAcceptFile = function (fileName) { var ok = tsExp.test(fileName); ok = ok && fileName.indexOf('_infrastructure') < 0; ok = ok && fileName.indexOf('node_modules/') < 0; ok = ok && /^[a-z]/i.test(fileName); return ok; }; TestRunner.prototype.run = function () { var _this = this; this.timer = new DT.Timer(); this.timer.start(); this.print.printChangeHeader(); // only includes .d.ts or -tests.ts or -test.ts or .ts return this.index.readIndex().then(function () { return _this.changes.readChanges(); }).then(function (changes) { _this.print.printAllChanges(changes); return _this.index.collectDiff(changes); }).then(function () { _this.print.printRemovals(_this.index.removed); _this.print.printRelChanges(_this.index.changed); return _this.index.parseFiles(); }).then(function () { if (_this.options.printRefMap) { _this.print.printRefMap(_this.index, _this.index.refMap); } if (Lazy(_this.index.missing).some(function (arr) { return arr.length > 0; })) { _this.print.printMissing(_this.index, _this.index.missing); _this.print.printBoldDiv(); // bail return Promise.cast(false); } if (_this.options.printFiles) { _this.print.printFiles(_this.index.files); } return _this.index.collectTargets().then(function (files) { if (_this.options.testChanges) { _this.print.printQueue(files); return _this.runTests(files); } else { _this.print.printTestAll(); return _this.runTests(_this.index.files); } }).then(function () { return !_this.suites.some(function (suite) { return suite.ngTests.length !== 0; }); }); }); }; TestRunner.prototype.runTests = function (files) { var _this = this; return Promise.attempt(function () { assert(Array.isArray(files), 'files must be array'); var syntaxChecking = new DT.SyntaxChecking(_this.options); var testEval = new DT.TestEval(_this.options); if (!_this.options.findNotRequiredTscparams) { _this.addSuite(syntaxChecking); _this.addSuite(testEval); } return Promise.all([ syntaxChecking.filterTargetFiles(files), testEval.filterTargetFiles(files) ]); }).spread(function (syntaxFiles, testFiles) { _this.print.init(syntaxFiles.length, testFiles.length, files.length); _this.print.printHeader(_this.options); if (_this.options.findNotRequiredTscparams) { _this.addSuite(new DT.FindNotRequiredTscparams(_this.options, _this.print)); } return Promise.reduce(_this.suites, function (count, suite) { suite.testReporter = suite.testReporter || new DT.DefaultTestReporter(_this.print); _this.print.printSuiteHeader(suite.testSuiteName); if (_this.options.skipTests) { _this.print.printWarnCode('skipped test'); return Promise.cast(count++); } return suite.start(files, function (testResult) { _this.print.printTestComplete(testResult); }).then(function (suite) { _this.print.printSuiteComplete(suite); return count++; }); }, 0); }).then(function (count) { _this.timer.end(); _this.finaliseTests(files); }); }; TestRunner.prototype.finaliseTests = function (files) { var _this = this; var testEval = Lazy(this.suites).filter(function (suite) { return suite instanceof DT.TestEval; }).first(); if (testEval) { var existsTestTypings = Lazy(testEval.testResults).map(function (testResult) { return testResult.targetFile.dir; }).reduce(function (a, b) { return a.indexOf(b) < 0 ? a.concat([b]) : a; }, []); var typings = Lazy(files).map(function (file) { return file.dir; }).reduce(function (a, b) { return a.indexOf(b) < 0 ? a.concat([b]) : a; }, []); var withoutTestTypings = typings.filter(function (typing) { return existsTestTypings.indexOf(typing) < 0; }); this.print.printDiv(); this.print.printTypingsWithoutTest(withoutTestTypings); } this.print.printDiv(); this.print.printTotalMessage(); this.print.printDiv(); this.print.printElapsedTime(this.timer.asString, this.timer.time); this.suites.filter(function (suite) { return suite.printErrorCount; }).forEach(function (suite) { _this.print.printSuiteErrorCount(suite.errorHeadline, suite.ngTests.length, suite.testResults.length); }); if (testEval) { this.print.printSuiteErrorCount('Without tests', withoutTestTypings.length, typings.length, true); } this.print.printDiv(); if (this.suites.some(function (suite) { return suite.ngTests.length !== 0; })) { this.print.printErrorsHeader(); this.suites.filter(function (suite) { return suite.ngTests.length !== 0; }).forEach(function (suite) { suite.ngTests.forEach(function (testResult) { _this.print.printErrorsForFile(testResult); }); _this.print.printBoldDiv(); }); } }; return TestRunner; })(); DT.TestRunner = TestRunner; var optimist = require('optimist')(process.argv); optimist.default('try-without-tscparams', false); optimist.default('single-thread', false); optimist.default('tsc-version', DT.DEFAULT_TSC_VERSION); optimist.default('test-changes', false); optimist.default('skip-tests', false); optimist.default('print-files', false); optimist.default('print-refmap', false); optimist.boolean('help'); optimist.describe('help', 'print help'); optimist.alias('h', 'help'); var argv = optimist.argv; var dtPath = path.resolve(path.dirname((module).filename), '..', '..'); var cpuCores = os.cpus().length; if (argv.help) { optimist.showHelp(); var pkg = require('../../package.json'); console.log('Scripts:'); console.log(''); Lazy(pkg.scripts).keys().each(function (key) { console.log(' $ npm run ' + key); }); process.exit(0); } var testFull = process.env['TRAVIS_BRANCH'] ? /\w\/full$/.test(process.env['TRAVIS_BRANCH']) : false; new TestRunner(dtPath, { concurrent: argv['single-thread'] ? 1 : Math.max(Math.min(24, cpuCores), 2), tscVersion: argv['tsc-version'], testChanges: testFull ? false : argv['test-changes'], skipTests: argv['skip-tests'], printFiles: argv['print-files'], printRefMap: argv['print-refmap'], findNotRequiredTscparams: argv['try-without-tscparam'] }).run().then(function (success) { if (!success) { process.exit(1); } }).catch(function (err) { throw err; process.exit(2); }); })(DT || (DT = {})); //# sourceMappingURL=runner.js.map