Comparing version 1.4.3 to 1.4.4
@@ -0,12 +1,8 @@ | ||
/* global __dirname */ | ||
var gulp = require('gulp'); | ||
var path = require('path'); | ||
var tsb = require('./src'); | ||
var compilation = tsb.create({ | ||
verbose: true, | ||
target: 'es5', | ||
module: 'commonjs', | ||
declaration: false, | ||
preserveConstEnums: true | ||
}); | ||
var compilation = tsb.create(path.join(__dirname, 'tsconfig.json'), true); | ||
@@ -13,0 +9,0 @@ var sources = [ |
{ | ||
"name": "gulp-tsb", | ||
"version": "1.4.3", | ||
"version": "1.4.4", | ||
"author": "Johannes Rieken <johannes.rieken@gmail.com>", | ||
@@ -21,3 +21,4 @@ "description": "A gulp plugin for very fast TypeScript compilation.", | ||
"through": "^2.3.6", | ||
"vinyl": "^0.4.3" | ||
"vinyl": "^0.4.3", | ||
"clone": "^0.2.0" | ||
}, | ||
@@ -24,0 +25,0 @@ "devDependencies": { |
@@ -16,7 +16,7 @@ /// <reference path="../typings/node/node.d.ts" /> | ||
function createTypeScriptBuilder(config) { | ||
var settings = createCompilationSettings(config), host = new LanguageServiceHost(settings), service = ts.createLanguageService(host, ts.createDocumentRegistry()), lastBuildVersion = Object.create(null), lastDtsHash = Object.create(null), userWantsDeclarations = settings.declaration, oldErrors = Object.create(null), headUsed = process.memoryUsage().heapUsed; | ||
var compilerOptions = createCompilerOptions(config), host = new LanguageServiceHost(compilerOptions), service = ts.createLanguageService(host, ts.createDocumentRegistry()), lastBuildVersion = Object.create(null), lastDtsHash = Object.create(null), userWantsDeclarations = compilerOptions.declaration, oldErrors = Object.create(null), headUsed = process.memoryUsage().heapUsed; | ||
// always emit declaraction files | ||
host.getCompilationSettings().declaration = true; | ||
if (!host.getCompilationSettings().noLib) { | ||
var defaultLib = host.getDefaultLibFilename(); | ||
var defaultLib = host.getDefaultLibFileName(); | ||
host.addScriptSnapshot(defaultLib, new ScriptSnapshot(fs.readFileSync(defaultLib), fs.statSync(defaultLib))); | ||
@@ -30,9 +30,9 @@ } | ||
function printDiagnostic(diag, onError) { | ||
var lineAndCh = diag.file.getLineAndCharacterFromPosition(diag.start), message; | ||
var lineAndCh = diag.file.getLineAndCharacterOfPosition(diag.start), message; | ||
if (!config.json) { | ||
message = utils.strings.format('{0}({1},{2}): {3}', diag.file.filename, lineAndCh.line, lineAndCh.character, diag.messageText); | ||
message = utils.strings.format('{0}({1},{2}): {3}', diag.file.fileName, lineAndCh.line + 1, lineAndCh.character + 1, diag.messageText); | ||
} | ||
else { | ||
message = JSON.stringify({ | ||
filename: diag.file.filename, | ||
filename: diag.file.fileName, | ||
offset: diag.start, | ||
@@ -60,12 +60,18 @@ length: diag.length, | ||
} | ||
function isExternalModule(sourceFile) { | ||
return !!sourceFile.externalModuleIndicator; | ||
} | ||
for (var i = 0, len = filenames.length; i < len; i++) { | ||
var filename = filenames[i], version = host.getScriptVersion(filename); | ||
if (lastBuildVersion[filename] === version) { | ||
// unchanged since the last time | ||
continue; | ||
} | ||
var output = service.getEmitOutput(filename), checkSyntax = false, checkSemantics = false, dtsHash = undefined; | ||
var output = service.getEmitOutput(filename), dtsHash = undefined; | ||
// emit output has fast as possible | ||
output.outputFiles.forEach(function (file) { | ||
if (/\.d\.ts$/.test(file.name)) { | ||
dtsHash = crypto.createHash('md5').update(file.text).digest('base64'); | ||
dtsHash = crypto.createHash('md5') | ||
.update(file.text) | ||
.digest('base64'); | ||
if (!userWantsDeclarations) { | ||
@@ -82,38 +88,12 @@ // don't leak .d.ts files if users don't want them | ||
}); | ||
switch (output.emitOutputStatus) { | ||
case ts.EmitReturnStatus.Succeeded: | ||
break; | ||
case ts.EmitReturnStatus.AllOutputGenerationSkipped: | ||
log('[syntax errors]', filename); | ||
checkSyntax = true; | ||
break; | ||
case ts.EmitReturnStatus.JSGeneratedWithSemanticErrors: | ||
case ts.EmitReturnStatus.DeclarationGenerationSkipped: | ||
log('[semantic errors]', filename); | ||
checkSemantics = true; | ||
break; | ||
case ts.EmitReturnStatus.EmitErrorsEncountered: | ||
case ts.EmitReturnStatus.CompilerOptionsErrors: | ||
default: | ||
// don't really know what to do with these | ||
checkSyntax = true; | ||
checkSemantics = true; | ||
break; | ||
} | ||
// print and store syntax and semantic errors | ||
delete oldErrors[filename]; | ||
var diagnostics = utils.collections.lookupOrInsert(newErrors, filename, []); | ||
if (checkSyntax) { | ||
diagnostics.push.apply(diagnostics, service.getSyntacticDiagnostics(filename)); | ||
} | ||
if (checkSemantics) { | ||
diagnostics.push.apply(diagnostics, service.getSemanticDiagnostics(filename)); | ||
} | ||
diagnostics.forEach(function (diag) { | ||
printDiagnostic(diag, onError); | ||
}); | ||
diagnostics.push.apply(diagnostics, service.getSyntacticDiagnostics(filename)); | ||
diagnostics.push.apply(diagnostics, service.getSemanticDiagnostics(filename)); | ||
diagnostics.forEach(function (diag) { return printDiagnostic(diag, onError); }); | ||
// dts comparing | ||
if (dtsHash && lastDtsHash[filename] !== dtsHash) { | ||
lastDtsHash[filename] = dtsHash; | ||
if (service.getSourceFile(filename).externalModuleIndicator) { | ||
if (isExternalModule(service.getSourceFile(filename))) { | ||
filesWithShapeChanges.push(filename); | ||
@@ -130,3 +110,3 @@ } | ||
} | ||
else if (!service.getSourceFile(filesWithShapeChanges[0]).externalModuleIndicator) { | ||
else if (!isExternalModule(service.getSourceFile(filesWithShapeChanges[0]))) { | ||
// at least one internal module changes which means that | ||
@@ -189,22 +169,22 @@ // we have to type check all others | ||
exports.createTypeScriptBuilder = createTypeScriptBuilder; | ||
function createCompilationSettings(config) { | ||
function createCompilerOptions(config) { | ||
// language version | ||
if (!config['target']) { | ||
config['target'] = ts.ScriptTarget.ES3; | ||
config['target'] = 0 /* ES3 */; | ||
} | ||
else if (/ES3/i.test(String(config['target']))) { | ||
config['target'] = ts.ScriptTarget.ES3; | ||
config['target'] = 0 /* ES3 */; | ||
} | ||
else if (/ES5/i.test(String(config['target']))) { | ||
config['target'] = ts.ScriptTarget.ES5; | ||
config['target'] = 1 /* ES5 */; | ||
} | ||
else if (/ES6/i.test(String(config['target']))) { | ||
config['target'] = ts.ScriptTarget.ES6; | ||
config['target'] = 2 /* ES6 */; | ||
} | ||
// module generation | ||
if (/commonjs/i.test(String(config['module']))) { | ||
config['module'] = ts.ModuleKind.CommonJS; | ||
config['module'] = 1 /* CommonJS */; | ||
} | ||
else if (/amd/i.test(String(config['module']))) { | ||
config['module'] = ts.ModuleKind.AMD; | ||
config['module'] = 2 /* AMD */; | ||
} | ||
@@ -216,3 +196,2 @@ return config; | ||
this._text = buffer.toString(); | ||
this._lineStarts = ts.computeLineStarts(this._text); | ||
this._mtime = stat.mtime; | ||
@@ -229,5 +208,2 @@ } | ||
}; | ||
ScriptSnapshot.prototype.getLineStartPositions = function () { | ||
return this._lineStarts; | ||
}; | ||
ScriptSnapshot.prototype.getChangeRange = function (oldSnapshot) { | ||
@@ -249,2 +225,8 @@ return null; | ||
}; | ||
LanguageServiceHost.prototype.trace = function (s) { | ||
// nothing | ||
}; | ||
LanguageServiceHost.prototype.error = function (s) { | ||
console.error(s); | ||
}; | ||
LanguageServiceHost.prototype.getCompilationSettings = function () { | ||
@@ -260,5 +242,2 @@ return this._settings; | ||
}; | ||
LanguageServiceHost.prototype.getScriptIsOpen = function (filename) { | ||
return false; | ||
}; | ||
LanguageServiceHost.prototype.getScriptSnapshot = function (filename) { | ||
@@ -290,3 +269,3 @@ filename = normalize(filename); | ||
}; | ||
LanguageServiceHost.prototype.getDefaultLibFilename = function () { | ||
LanguageServiceHost.prototype.getDefaultLibFileName = function () { | ||
return this._defaultLib; | ||
@@ -314,3 +293,3 @@ }; | ||
info.referencedFiles.forEach(function (ref) { | ||
var resolvedPath = path.resolve(path.dirname(filename), ref.filename), normalizedPath = normalize(resolvedPath); | ||
var resolvedPath = path.resolve(path.dirname(filename), ref.fileName), normalizedPath = normalize(resolvedPath); | ||
_this._dependencies.inertEdge(filename, normalizedPath); | ||
@@ -323,3 +302,3 @@ }); | ||
dirname = path.dirname(dirname); | ||
var resolvedPath = path.resolve(dirname, ref.filename), normalizedPath = normalize(resolvedPath); | ||
var resolvedPath = path.resolve(dirname, ref.fileName), normalizedPath = normalize(resolvedPath); | ||
if (_this.getScriptSnapshot(normalizedPath + '.ts')) { | ||
@@ -326,0 +305,0 @@ _this._dependencies.inertEdge(filename, normalizedPath + '.ts'); |
@@ -16,14 +16,14 @@ /// <reference path="../typings/node/node.d.ts" /> | ||
export interface IConfiguration { | ||
json: boolean; | ||
verbose: boolean; | ||
[option: string]: string | number | boolean; | ||
json: boolean; | ||
verbose: boolean; | ||
[option: string]: string | number | boolean; | ||
} | ||
export interface ITypeScriptBuilder { | ||
build(out: (file: Vinyl) => void, onError: (err: any) => void): void; | ||
file(file: Vinyl): void; | ||
build(out: (file: Vinyl) => void, onError: (err: any) => void): void; | ||
file(file: Vinyl): void; | ||
} | ||
function normalize(path: string): string { | ||
return path.replace(/\\/g, '/'); | ||
function normalize(path: string): string { | ||
return path.replace(/\\/g, '/'); | ||
} | ||
@@ -33,254 +33,227 @@ | ||
var settings = createCompilationSettings(config), | ||
host = new LanguageServiceHost(settings), | ||
service = ts.createLanguageService(host, ts.createDocumentRegistry()), | ||
lastBuildVersion: { [path: string]: string } = Object.create(null), | ||
lastDtsHash: { [path: string]: string } = Object.create(null), | ||
userWantsDeclarations = settings.declaration, | ||
oldErrors: { [path: string]: ts.Diagnostic[] } = Object.create(null), | ||
headUsed = process.memoryUsage().heapUsed; | ||
var compilerOptions = createCompilerOptions(config), | ||
host = new LanguageServiceHost(compilerOptions), | ||
service = ts.createLanguageService(host, ts.createDocumentRegistry()), | ||
lastBuildVersion: { [path: string]: string } = Object.create(null), | ||
lastDtsHash: { [path: string]: string } = Object.create(null), | ||
userWantsDeclarations = compilerOptions.declaration, | ||
oldErrors: { [path: string]: ts.Diagnostic[] } = Object.create(null), | ||
headUsed = process.memoryUsage().heapUsed; | ||
// always emit declaraction files | ||
host.getCompilationSettings().declaration = true; | ||
if (!host.getCompilationSettings().noLib) { | ||
var defaultLib = host.getDefaultLibFilename(); | ||
host.addScriptSnapshot(defaultLib, new ScriptSnapshot(fs.readFileSync(defaultLib), fs.statSync(defaultLib))); | ||
} | ||
function log(topic: string, message: string): void { | ||
if(config.verbose) { | ||
gutil.log(gutil.colors.cyan(topic), message); | ||
} | ||
} | ||
function printDiagnostic(diag: ts.Diagnostic, onError: (err: any) => void): void { | ||
// always emit declaraction files | ||
host.getCompilationSettings().declaration = true; | ||
var lineAndCh = diag.file.getLineAndCharacterFromPosition(diag.start), | ||
message: string; | ||
if (!host.getCompilationSettings().noLib) { | ||
var defaultLib = host.getDefaultLibFileName(); | ||
host.addScriptSnapshot(defaultLib, new ScriptSnapshot(fs.readFileSync(defaultLib), fs.statSync(defaultLib))); | ||
} | ||
if (!config.json) { | ||
message = utils.strings.format('{0}({1},{2}): {3}', | ||
diag.file.filename, | ||
lineAndCh.line, | ||
lineAndCh.character, | ||
diag.messageText); | ||
function log(topic: string, message: string): void { | ||
if (config.verbose) { | ||
gutil.log(gutil.colors.cyan(topic), message); | ||
} | ||
} | ||
} else { | ||
message = JSON.stringify({ | ||
filename: diag.file.filename, | ||
offset: diag.start, | ||
length: diag.length, | ||
message: diag.messageText | ||
}); | ||
} | ||
function printDiagnostic(diag: ts.Diagnostic, onError: (err: any) => void): void { | ||
onError(message); | ||
} | ||
var lineAndCh = diag.file.getLineAndCharacterOfPosition(diag.start), | ||
message: string; | ||
function file(file: Vinyl): void { | ||
var snapshot = new ScriptSnapshot(file.contents, file.stat); | ||
host.addScriptSnapshot(file.path, snapshot); | ||
} | ||
if (!config.json) { | ||
message = utils.strings.format('{0}({1},{2}): {3}', | ||
diag.file.fileName, | ||
lineAndCh.line + 1, | ||
lineAndCh.character + 1, | ||
diag.messageText); | ||
function build(out: (file: Vinyl) => void, onError: (err: any) => void): void { | ||
} else { | ||
message = JSON.stringify({ | ||
filename: diag.file.fileName, | ||
offset: diag.start, | ||
length: diag.length, | ||
message: diag.messageText | ||
}); | ||
} | ||
var filenames = host.getScriptFileNames(), | ||
newErrors: { [path: string]: ts.Diagnostic[] } = Object.create(null), | ||
checkedThisRound: { [path: string]: boolean } = Object.create(null), | ||
filesWithShapeChanges: string[] = [], | ||
t1 = Date.now(); | ||
function shouldCheck(filename: string): boolean { | ||
if (checkedThisRound[filename]) { | ||
return false; | ||
} else { | ||
checkedThisRound[filename] = true; | ||
return true; | ||
} | ||
} | ||
for (var i = 0, len = filenames.length; i < len; i++) { | ||
onError(message); | ||
} | ||
var filename = filenames[i], | ||
version = host.getScriptVersion(filename); | ||
function file(file: Vinyl): void { | ||
var snapshot = new ScriptSnapshot(file.contents, file.stat); | ||
host.addScriptSnapshot(file.path, snapshot); | ||
} | ||
if (lastBuildVersion[filename] === version) { | ||
// unchanged since the last time | ||
continue; | ||
} | ||
function build(out: (file: Vinyl) => void, onError: (err: any) => void): void { | ||
var output = service.getEmitOutput(filename), | ||
checkSyntax = false, | ||
checkSemantics = false, | ||
dtsHash: string = undefined; | ||
// emit output has fast as possible | ||
output.outputFiles.forEach(file => { | ||
var filenames = host.getScriptFileNames(), | ||
newErrors: { [path: string]: ts.Diagnostic[] } = Object.create(null), | ||
checkedThisRound: { [path: string]: boolean } = Object.create(null), | ||
filesWithShapeChanges: string[] = [], | ||
t1 = Date.now(); | ||
if (/\.d\.ts$/.test(file.name)) { | ||
function shouldCheck(filename: string): boolean { | ||
if (checkedThisRound[filename]) { | ||
return false; | ||
} else { | ||
checkedThisRound[filename] = true; | ||
return true; | ||
} | ||
} | ||
function isExternalModule(sourceFile: ts.SourceFile): boolean { | ||
return !!(<any> sourceFile).externalModuleIndicator; | ||
} | ||
for (var i = 0, len = filenames.length; i < len; i++) { | ||
dtsHash = crypto.createHash('md5') | ||
.update(file.text) | ||
.digest('base64'); | ||
var filename = filenames[i], | ||
version = host.getScriptVersion(filename); | ||
if (!userWantsDeclarations) { | ||
// don't leak .d.ts files if users don't want them | ||
return; | ||
} | ||
} | ||
log('[emit output]', file.name); | ||
out(new Vinyl({ | ||
path: file.name, | ||
contents: new Buffer(file.text) | ||
})); | ||
}); | ||
if (lastBuildVersion[filename] === version) { | ||
// unchanged since the last time | ||
continue; | ||
} | ||
var output = service.getEmitOutput(filename), | ||
dtsHash: string = undefined; | ||
// make use of emit status | ||
switch (output.emitOutputStatus) { | ||
case ts.EmitReturnStatus.Succeeded: | ||
// good | ||
break; | ||
case ts.EmitReturnStatus.AllOutputGenerationSkipped: | ||
log('[syntax errors]', filename); | ||
checkSyntax = true; | ||
break; | ||
case ts.EmitReturnStatus.JSGeneratedWithSemanticErrors: | ||
case ts.EmitReturnStatus.DeclarationGenerationSkipped: | ||
log('[semantic errors]', filename); | ||
checkSemantics = true; | ||
break; | ||
case ts.EmitReturnStatus.EmitErrorsEncountered: | ||
case ts.EmitReturnStatus.CompilerOptionsErrors: | ||
default: | ||
// don't really know what to do with these | ||
checkSyntax = true; | ||
checkSemantics = true; | ||
break; | ||
} | ||
// print and store syntax and semantic errors | ||
delete oldErrors[filename]; | ||
var diagnostics = utils.collections.lookupOrInsert(newErrors, filename, []); | ||
if (checkSyntax) { | ||
diagnostics.push.apply(diagnostics, service.getSyntacticDiagnostics(filename)); | ||
} | ||
if (checkSemantics) { | ||
diagnostics.push.apply(diagnostics, service.getSemanticDiagnostics(filename)); | ||
} | ||
diagnostics.forEach(diag => { | ||
printDiagnostic(diag, onError); | ||
}); | ||
// dts comparing | ||
if (dtsHash && lastDtsHash[filename] !== dtsHash) { | ||
lastDtsHash[filename] = dtsHash; | ||
if (service.getSourceFile(filename).externalModuleIndicator) { | ||
filesWithShapeChanges.push(filename); | ||
} else { | ||
filesWithShapeChanges.unshift(filename); | ||
} | ||
} | ||
// emit output has fast as possible | ||
output.outputFiles.forEach(file => { | ||
lastBuildVersion[filename] = version; | ||
checkedThisRound[filename] = true; | ||
} | ||
if (filesWithShapeChanges.length === 0) { | ||
// nothing to do here | ||
if (/\.d\.ts$/.test(file.name)) { | ||
dtsHash = crypto.createHash('md5') | ||
.update(file.text) | ||
.digest('base64'); | ||
if (!userWantsDeclarations) { | ||
// don't leak .d.ts files if users don't want them | ||
return; | ||
} | ||
} | ||
log('[emit output]', file.name); | ||
out(new Vinyl({ | ||
path: file.name, | ||
contents: new Buffer(file.text) | ||
})); | ||
}); | ||
// print and store syntax and semantic errors | ||
delete oldErrors[filename]; | ||
var diagnostics = utils.collections.lookupOrInsert(newErrors, filename, []); | ||
diagnostics.push.apply(diagnostics, service.getSyntacticDiagnostics(filename)); | ||
diagnostics.push.apply(diagnostics, service.getSemanticDiagnostics(filename)); | ||
diagnostics.forEach(diag => printDiagnostic(diag, onError)); | ||
// dts comparing | ||
if (dtsHash && lastDtsHash[filename] !== dtsHash) { | ||
lastDtsHash[filename] = dtsHash; | ||
if (isExternalModule(service.getSourceFile(filename))) { | ||
filesWithShapeChanges.push(filename); | ||
} else { | ||
filesWithShapeChanges.unshift(filename); | ||
} | ||
} | ||
lastBuildVersion[filename] = version; | ||
checkedThisRound[filename] = true; | ||
} | ||
if (filesWithShapeChanges.length === 0) { | ||
// nothing to do here | ||
} else if (!service.getSourceFile(filesWithShapeChanges[0]).externalModuleIndicator) { | ||
// at least one internal module changes which means that | ||
// we have to type check all others | ||
log('[shape changes]', 'internal module changed → FULL check required'); | ||
host.getScriptFileNames().forEach(filename => { | ||
if(!shouldCheck(filename)) { | ||
return; | ||
} | ||
log('[semantic check*]', filename); | ||
delete oldErrors[filename]; | ||
var diagnostics = utils.collections.lookupOrInsert(newErrors, filename, []); | ||
service.getSemanticDiagnostics(filename).forEach(diag => { | ||
diagnostics.push(diag); | ||
printDiagnostic(diag, onError); | ||
}); | ||
}); | ||
} else { | ||
// reverse dependencies | ||
log('[shape changes]', 'external module changed → check REVERSE dependencies'); | ||
var needsSemanticCheck: string[] = []; | ||
filesWithShapeChanges.forEach(filename => host.collectDependents(filename, needsSemanticCheck)); | ||
while(needsSemanticCheck.length) { | ||
var filename = needsSemanticCheck.pop(); | ||
if(!shouldCheck(filename)) { | ||
continue; | ||
} | ||
log('[semantic check*]', filename); | ||
delete oldErrors[filename]; | ||
var diagnostics = utils.collections.lookupOrInsert(newErrors, filename, []), | ||
hasSemanticErrors = false; | ||
service.getSemanticDiagnostics(filename).forEach(diag => { | ||
diagnostics.push(diag); | ||
printDiagnostic(diag, onError); | ||
hasSemanticErrors = true; | ||
}); | ||
if(!hasSemanticErrors) { | ||
host.collectDependents(filename, needsSemanticCheck); | ||
} | ||
} | ||
} | ||
// (4) dump old errors | ||
utils.collections.forEach(oldErrors, entry => { | ||
entry.value.forEach(diag => printDiagnostic(diag, onError)); | ||
newErrors[entry.key] = entry.value; | ||
}); | ||
} else if (!isExternalModule(service.getSourceFile(filesWithShapeChanges[0]))) { | ||
// at least one internal module changes which means that | ||
// we have to type check all others | ||
log('[shape changes]', 'internal module changed → FULL check required'); | ||
host.getScriptFileNames().forEach(filename => { | ||
if (!shouldCheck(filename)) { | ||
return; | ||
} | ||
log('[semantic check*]', filename); | ||
delete oldErrors[filename]; | ||
var diagnostics = utils.collections.lookupOrInsert(newErrors, filename, []); | ||
service.getSemanticDiagnostics(filename).forEach(diag => { | ||
diagnostics.push(diag); | ||
printDiagnostic(diag, onError); | ||
}); | ||
}); | ||
} else { | ||
// reverse dependencies | ||
log('[shape changes]', 'external module changed → check REVERSE dependencies'); | ||
var needsSemanticCheck: string[] = []; | ||
filesWithShapeChanges.forEach(filename => host.collectDependents(filename, needsSemanticCheck)); | ||
while (needsSemanticCheck.length) { | ||
var filename = needsSemanticCheck.pop(); | ||
if (!shouldCheck(filename)) { | ||
continue; | ||
} | ||
log('[semantic check*]', filename); | ||
delete oldErrors[filename]; | ||
var diagnostics = utils.collections.lookupOrInsert(newErrors, filename, []), | ||
hasSemanticErrors = false; | ||
oldErrors = newErrors; | ||
service.getSemanticDiagnostics(filename).forEach(diag => { | ||
diagnostics.push(diag); | ||
printDiagnostic(diag, onError); | ||
hasSemanticErrors = true; | ||
}); | ||
if (!hasSemanticErrors) { | ||
host.collectDependents(filename, needsSemanticCheck); | ||
} | ||
} | ||
} | ||
if (config.verbose) { | ||
var headNow = process.memoryUsage().heapUsed, | ||
MB = 1024 * 1024; | ||
gutil.log( | ||
'[tsb]', | ||
'time:', | ||
gutil.colors.yellow((Date.now() - t1) + 'ms'), | ||
'mem:', | ||
gutil.colors.cyan(Math.ceil(headNow / MB) + 'MB'), | ||
gutil.colors.bgCyan('Δ' + Math.ceil((headNow - headUsed) / MB))); | ||
headUsed = headNow; | ||
} | ||
} | ||
// (4) dump old errors | ||
utils.collections.forEach(oldErrors, entry => { | ||
entry.value.forEach(diag => printDiagnostic(diag, onError)); | ||
newErrors[entry.key] = entry.value; | ||
}); | ||
return { | ||
file, | ||
build | ||
}; | ||
oldErrors = newErrors; | ||
if (config.verbose) { | ||
var headNow = process.memoryUsage().heapUsed, | ||
MB = 1024 * 1024; | ||
gutil.log( | ||
'[tsb]', | ||
'time:', | ||
gutil.colors.yellow((Date.now() - t1) + 'ms'), | ||
'mem:', | ||
gutil.colors.cyan(Math.ceil(headNow / MB) + 'MB'), | ||
gutil.colors.bgCyan('Δ' + Math.ceil((headNow - headUsed) / MB))); | ||
headUsed = headNow; | ||
} | ||
} | ||
return { | ||
file, | ||
build | ||
}; | ||
} | ||
function createCompilationSettings(config: IConfiguration): ts.CompilerOptions { | ||
function createCompilerOptions(config: IConfiguration): ts.CompilerOptions { | ||
// language version | ||
if (!config['target']) { | ||
config['target'] = ts.ScriptTarget.ES3; | ||
} else if (/ES3/i.test(String(config['target']))) { | ||
config['target'] = ts.ScriptTarget.ES3; | ||
} else if (/ES5/i.test(String(config['target']))) { | ||
config['target'] = ts.ScriptTarget.ES5; | ||
} else if (/ES6/i.test(String(config['target']))) { | ||
config['target'] = ts.ScriptTarget.ES6; | ||
} | ||
// language version | ||
if (!config['target']) { | ||
config['target'] = ts.ScriptTarget.ES3; | ||
} else if (/ES3/i.test(String(config['target']))) { | ||
config['target'] = ts.ScriptTarget.ES3; | ||
} else if (/ES5/i.test(String(config['target']))) { | ||
config['target'] = ts.ScriptTarget.ES5; | ||
} else if (/ES6/i.test(String(config['target']))) { | ||
config['target'] = ts.ScriptTarget.ES6; | ||
} | ||
// module generation | ||
if (/commonjs/i.test(String(config['module']))) { | ||
config['module'] = ts.ModuleKind.CommonJS; | ||
} else if (/amd/i.test(String(config['module']))) { | ||
config['module'] = ts.ModuleKind.AMD; | ||
} | ||
// module generation | ||
if (/commonjs/i.test(String(config['module']))) { | ||
config['module'] = ts.ModuleKind.CommonJS; | ||
} else if (/amd/i.test(String(config['module']))) { | ||
config['module'] = ts.ModuleKind.AMD; | ||
} | ||
return <ts.CompilerOptions> config; | ||
return <ts.CompilerOptions> config; | ||
} | ||
@@ -290,15 +263,13 @@ | ||
private _text: string; | ||
private _lineStarts: number[]; | ||
private _mtime: Date; | ||
private _text: string; | ||
private _mtime: Date; | ||
constructor(buffer: Buffer, stat: fs.Stats) { | ||
this._text = buffer.toString(); | ||
this._lineStarts = ts.computeLineStarts(this._text); | ||
this._mtime = stat.mtime; | ||
this._text = buffer.toString(); | ||
this._mtime = stat.mtime; | ||
} | ||
public getVersion(): string { | ||
return this._mtime.toUTCString(); | ||
} | ||
public getVersion(): string { | ||
return this._mtime.toUTCString(); | ||
} | ||
@@ -313,9 +284,5 @@ public getText(start: number, end: number): string { | ||
public getLineStartPositions(): number[] { | ||
return this._lineStarts; | ||
public getChangeRange(oldSnapshot: ts.IScriptSnapshot): ts.TextChangeRange { | ||
return null; | ||
} | ||
public getChangeRange(oldSnapshot: ts.IScriptSnapshot): ts.TextChangeRange { | ||
return null; | ||
} | ||
} | ||
@@ -325,123 +292,127 @@ | ||
private _settings: ts.CompilerOptions; | ||
private _snapshots: { [path: string]: ScriptSnapshot }; | ||
private _defaultLib: string; | ||
private _dependencies: utils.graph.Graph<string>; | ||
private _dependenciesRecomputeList: string[]; | ||
private _settings: ts.CompilerOptions; | ||
private _snapshots: { [path: string]: ScriptSnapshot }; | ||
private _defaultLib: string; | ||
private _dependencies: utils.graph.Graph<string>; | ||
private _dependenciesRecomputeList: string[]; | ||
constructor(settings: ts.CompilerOptions) { | ||
this._settings = settings; | ||
this._snapshots = Object.create(null); | ||
this._defaultLib = normalize(path.join(__dirname, 'typescript', 'lib.d.ts')); | ||
this._dependencies = new utils.graph.Graph<string>(s => s); | ||
this._dependenciesRecomputeList = []; | ||
} | ||
constructor(settings: ts.CompilerOptions) { | ||
this._settings = settings; | ||
this._snapshots = Object.create(null); | ||
this._defaultLib = normalize(path.join(__dirname, 'typescript', 'lib.d.ts')); | ||
this._dependencies = new utils.graph.Graph<string>(s => s); | ||
this._dependenciesRecomputeList = []; | ||
} | ||
log(s: string): void { | ||
// nothing | ||
} | ||
log(s: string): void { | ||
// nothing | ||
} | ||
getCompilationSettings(): ts.CompilerOptions { | ||
return this._settings; | ||
} | ||
trace(s: string): void { | ||
// nothing | ||
} | ||
error(s: string): void { | ||
console.error(s); | ||
} | ||
getCompilationSettings(): ts.CompilerOptions { | ||
return this._settings; | ||
} | ||
getScriptFileNames(): string[] { | ||
return Object.keys(this._snapshots); | ||
} | ||
return Object.keys(this._snapshots); | ||
} | ||
getScriptVersion(filename: string): string { | ||
filename = normalize(filename); | ||
return this._snapshots[filename].getVersion(); | ||
} | ||
filename = normalize(filename); | ||
return this._snapshots[filename].getVersion(); | ||
} | ||
getScriptIsOpen(filename: string): boolean { | ||
return false; | ||
} | ||
getScriptSnapshot(filename: string): ts.IScriptSnapshot { | ||
filename = normalize(filename); | ||
return this._snapshots[filename]; | ||
} | ||
filename = normalize(filename); | ||
return this._snapshots[filename]; | ||
} | ||
addScriptSnapshot(filename: string, snapshot: ScriptSnapshot): ScriptSnapshot { | ||
filename = normalize(filename); | ||
var old = this._snapshots[filename]; | ||
if(!old || old.getVersion() !== snapshot.getVersion()) { | ||
this._dependenciesRecomputeList.push(filename); | ||
var node = this._dependencies.lookup(filename); | ||
if(node) { | ||
node.outgoing = Object.create(null); | ||
} | ||
} | ||
this._snapshots[filename] = snapshot; | ||
return old; | ||
} | ||
addScriptSnapshot(filename: string, snapshot: ScriptSnapshot): ScriptSnapshot { | ||
filename = normalize(filename); | ||
var old = this._snapshots[filename]; | ||
if (!old || old.getVersion() !== snapshot.getVersion()) { | ||
this._dependenciesRecomputeList.push(filename); | ||
var node = this._dependencies.lookup(filename); | ||
if (node) { | ||
node.outgoing = Object.create(null); | ||
} | ||
} | ||
this._snapshots[filename] = snapshot; | ||
return old; | ||
} | ||
getLocalizedDiagnosticMessages(): any { | ||
return null; | ||
} | ||
return null; | ||
} | ||
getCancellationToken(): ts.CancellationToken { | ||
return { isCancellationRequested: () => false }; | ||
} | ||
return { isCancellationRequested: () => false }; | ||
} | ||
getCurrentDirectory(): string { | ||
return process.cwd(); | ||
} | ||
getCurrentDirectory(): string { | ||
return process.cwd(); | ||
} | ||
getDefaultLibFilename(): string { | ||
return this._defaultLib; | ||
} | ||
getDefaultLibFileName(): string { | ||
return this._defaultLib; | ||
} | ||
// ---- dependency management | ||
// ---- dependency management | ||
collectDependents(filename: string, target: string[]): void { | ||
while (this._dependenciesRecomputeList.length) { | ||
this._processFile(this._dependenciesRecomputeList.pop()); | ||
} | ||
filename = normalize(filename); | ||
var node = this._dependencies.lookup(filename); | ||
if (node) { | ||
utils.collections.forEach(node.incoming, entry => target.push(entry.key)); | ||
} | ||
} | ||
_processFile(filename: string): void { | ||
if(filename.match(/.*\.d\.ts$/)) { | ||
return; | ||
} | ||
filename = normalize(filename); | ||
var snapshot = this.getScriptSnapshot(filename), | ||
info = ts.preProcessFile(snapshot.getText(0, snapshot.getLength()), true); | ||
collectDependents(filename: string, target: string[]): void { | ||
while (this._dependenciesRecomputeList.length) { | ||
this._processFile(this._dependenciesRecomputeList.pop()); | ||
} | ||
filename = normalize(filename); | ||
var node = this._dependencies.lookup(filename); | ||
if (node) { | ||
utils.collections.forEach(node.incoming, entry => target.push(entry.key)); | ||
} | ||
} | ||
_processFile(filename: string): void { | ||
if (filename.match(/.*\.d\.ts$/)) { | ||
return; | ||
} | ||
filename = normalize(filename); | ||
var snapshot = this.getScriptSnapshot(filename), | ||
info = ts.preProcessFile(snapshot.getText(0, snapshot.getLength()), true); | ||
// (1) ///-references | ||
info.referencedFiles.forEach(ref => { | ||
var resolvedPath = path.resolve(path.dirname(filename), ref.filename), | ||
normalizedPath = normalize(resolvedPath); | ||
// (1) ///-references | ||
info.referencedFiles.forEach(ref => { | ||
var resolvedPath = path.resolve(path.dirname(filename), ref.fileName), | ||
normalizedPath = normalize(resolvedPath); | ||
this._dependencies.inertEdge(filename, normalizedPath); | ||
}); | ||
this._dependencies.inertEdge(filename, normalizedPath); | ||
}); | ||
// (2) import-require statements | ||
info.importedFiles.forEach(ref => { | ||
var stopDirname = normalize(this.getCurrentDirectory()), | ||
dirname = filename, | ||
found = false; | ||
// (2) import-require statements | ||
info.importedFiles.forEach(ref => { | ||
var stopDirname = normalize(this.getCurrentDirectory()), | ||
dirname = filename, | ||
found = false; | ||
while (!found && dirname.indexOf(stopDirname) === 0) { | ||
dirname = path.dirname(dirname); | ||
var resolvedPath = path.resolve(dirname, ref.filename), | ||
normalizedPath = normalize(resolvedPath); | ||
if(this.getScriptSnapshot(normalizedPath + '.ts')) { | ||
this._dependencies.inertEdge(filename, normalizedPath + '.ts'); | ||
found = true; | ||
} else if(this.getScriptSnapshot(normalizedPath + '.d.ts')) { | ||
this._dependencies.inertEdge(filename, normalizedPath + '.d.ts'); | ||
found = true; | ||
} | ||
} | ||
}); | ||
} | ||
while (!found && dirname.indexOf(stopDirname) === 0) { | ||
dirname = path.dirname(dirname); | ||
var resolvedPath = path.resolve(dirname, ref.fileName), | ||
normalizedPath = normalize(resolvedPath); | ||
if (this.getScriptSnapshot(normalizedPath + '.ts')) { | ||
this._dependencies.inertEdge(filename, normalizedPath + '.ts'); | ||
found = true; | ||
} else if (this.getScriptSnapshot(normalizedPath + '.d.ts')) { | ||
this._dependencies.inertEdge(filename, normalizedPath + '.d.ts'); | ||
found = true; | ||
} | ||
} | ||
}); | ||
} | ||
} |
/// <reference path="../typings/node/node.d.ts" /> | ||
/// <reference path="../typings/vinyl/vinyl.d.ts" /> | ||
/// <reference path="../typings/through/through.d.ts" /> | ||
/// <reference path="../typings/clone/clone.d.ts" /> | ||
var builder = require('./builder'); | ||
var through = require('through'); | ||
function create(config) { | ||
var clone = require('clone'); | ||
var fs = require('fs'); | ||
function create(configOrName, verbose, json) { | ||
var config; | ||
if (typeof configOrName === 'string') { | ||
try { | ||
var buffer = fs.readFileSync(configOrName); | ||
config = JSON.parse(buffer.toString())['compilerOptions']; | ||
} | ||
catch (e) { | ||
console.error(e); | ||
throw e; | ||
} | ||
} | ||
else { | ||
// clone the configuration | ||
config = clone(configOrName); | ||
} | ||
// add those | ||
config.verbose = config.verbose || verbose; | ||
config.json = config.json || json; | ||
var _builder = builder.createTypeScriptBuilder(config); | ||
@@ -8,0 +29,0 @@ function createStream() { |
/// <reference path="../typings/node/node.d.ts" /> | ||
/// <reference path="../typings/vinyl/vinyl.d.ts" /> | ||
/// <reference path="../typings/through/through.d.ts" /> | ||
/// <reference path="../typings/clone/clone.d.ts" /> | ||
@@ -9,12 +10,34 @@ import stream = require('stream'); | ||
import through = require('through'); | ||
import clone = require('clone'); | ||
import fs = require('fs'); | ||
import path = require('path'); | ||
export function create(config:builder.IConfiguration):()=>stream.Stream { | ||
export function create(configOrName: builder.IConfiguration|string, verbose?:boolean, json?:boolean): () => stream.Stream { | ||
var config: builder.IConfiguration; | ||
if (typeof configOrName === 'string') { | ||
try { | ||
var buffer = fs.readFileSync(configOrName); | ||
config = JSON.parse(buffer.toString())['compilerOptions']; | ||
} catch (e) { | ||
console.error(e); | ||
throw e; | ||
} | ||
} else { | ||
// clone the configuration | ||
config = clone(configOrName); | ||
} | ||
// add those | ||
config.verbose = config.verbose || verbose; | ||
config.json = config.json || json; | ||
var _builder = builder.createTypeScriptBuilder(config); | ||
function createStream():stream.Stream { | ||
return through(function(file: vinyl) { | ||
function createStream(): stream.Stream { | ||
return through(function (file: vinyl) { | ||
// give the file to the compiler | ||
if(file.isStream()) { | ||
if (file.isStream()) { | ||
this.emit('error', 'no support for streams'); | ||
@@ -24,11 +47,11 @@ return; | ||
_builder.file(file); | ||
}, function () { | ||
// start the compilation process | ||
_builder.build(file => this.queue(file), err => console.log(err)); | ||
this.queue(null); | ||
}); | ||
// start the compilation process | ||
_builder.build(file => this.queue(file), err => console.log(err)); | ||
this.queue(null); | ||
}); | ||
} | ||
return () => createStream(); | ||
} | ||
} |
200
src/utils.ts
export module collections { | ||
var hasOwnProperty = Object.prototype.hasOwnProperty; | ||
var hasOwnProperty = Object.prototype.hasOwnProperty; | ||
export function lookup<T>(collection: { [keys: string]: T }, key: string): T { | ||
if (hasOwnProperty.call(collection, key)) { | ||
return collection[key]; | ||
} | ||
return null; | ||
} | ||
export function lookup<T>(collection: { [keys: string]: T }, key: string): T { | ||
if (hasOwnProperty.call(collection, key)) { | ||
return collection[key]; | ||
} | ||
return null; | ||
} | ||
export function insert<T>(collection: { [keys: string]: T }, key: string, value: T): void { | ||
collection[key] = value; | ||
} | ||
export function insert<T>(collection: { [keys: string]: T }, key: string, value: T): void { | ||
collection[key] = value; | ||
} | ||
export function lookupOrInsert<T>(collection: { [keys: string]: T }, key: string, value: T): T { | ||
if (hasOwnProperty.call(collection, key)) { | ||
return collection[key]; | ||
} else { | ||
collection[key] = value; | ||
return value; | ||
} | ||
} | ||
export function lookupOrInsert<T>(collection: { [keys: string]: T }, key: string, value: T): T { | ||
if (hasOwnProperty.call(collection, key)) { | ||
return collection[key]; | ||
} else { | ||
collection[key] = value; | ||
return value; | ||
} | ||
} | ||
export function forEach<T>(collection: { [keys: string]: T }, callback: (entry: { key: string; value: T; }) => void): void { | ||
for (var key in collection) { | ||
if (hasOwnProperty.call(collection, key)) { | ||
callback({ | ||
key: key, | ||
value: collection[key] | ||
}); | ||
} | ||
} | ||
} | ||
export function forEach<T>(collection: { [keys: string]: T }, callback: (entry: { key: string; value: T; }) => void): void { | ||
for (var key in collection) { | ||
if (hasOwnProperty.call(collection, key)) { | ||
callback({ | ||
key: key, | ||
value: collection[key] | ||
}); | ||
} | ||
} | ||
} | ||
export function contains(collection: { [keys: string]: any }, key: string): boolean { | ||
return hasOwnProperty.call(collection, key); | ||
} | ||
export function contains(collection: { [keys: string]: any }, key: string): boolean { | ||
return hasOwnProperty.call(collection, key); | ||
} | ||
} | ||
@@ -47,12 +47,12 @@ | ||
*/ | ||
export var empty = ''; | ||
export var empty = ''; | ||
export var eolUnix = '\r\n'; | ||
export var eolUnix = '\r\n'; | ||
export function format(value: string, ...rest: any[]): string { | ||
return value.replace(/({\d+})/g, function (match) { | ||
var index = match.substring(1, match.length - 1); | ||
return rest[index] || match; | ||
}); | ||
} | ||
export function format(value: string, ...rest: any[]): string { | ||
return value.replace(/({\d+})/g, function (match) { | ||
var index = match.substring(1, match.length - 1); | ||
return rest[index] || match; | ||
}); | ||
} | ||
} | ||
@@ -62,77 +62,77 @@ | ||
export interface Node<T> { | ||
data: T; | ||
incoming: { [key: string]: Node<T> }; | ||
outgoing: { [key: string]: Node<T> }; | ||
} | ||
export interface Node<T> { | ||
data: T; | ||
incoming: { [key: string]: Node<T> }; | ||
outgoing: { [key: string]: Node<T> }; | ||
} | ||
export function newNode<T>(data: T): Node<T> { | ||
return { | ||
data: data, | ||
incoming: {}, | ||
outgoing: {} | ||
}; | ||
} | ||
export function newNode<T>(data: T): Node<T> { | ||
return { | ||
data: data, | ||
incoming: {}, | ||
outgoing: {} | ||
}; | ||
} | ||
export class Graph<T> { | ||
export class Graph<T> { | ||
private _nodes: { [key: string]: Node<T> } = {}; | ||
private _nodes: { [key: string]: Node<T> } = {}; | ||
constructor(private _hashFn: (element: T) => string) { | ||
// empty | ||
} | ||
constructor(private _hashFn: (element: T) => string) { | ||
// empty | ||
} | ||
public traverse(start: T, inwards: boolean, callback: (data: T) => void): void { | ||
var startNode = this.lookup(start); | ||
if (!startNode) { | ||
return; | ||
} | ||
this._traverse(startNode, inwards, {}, callback); | ||
} | ||
public traverse(start: T, inwards: boolean, callback: (data: T) => void): void { | ||
var startNode = this.lookup(start); | ||
if (!startNode) { | ||
return; | ||
} | ||
this._traverse(startNode, inwards, {}, callback); | ||
} | ||
private _traverse(node: Node<T>, inwards: boolean, seen: { [key: string]: boolean }, callback: (data: T) => void): void { | ||
var key = this._hashFn(node.data); | ||
if (collections.contains(seen, key)) { | ||
return; | ||
} | ||
seen[key] = true; | ||
callback(node.data); | ||
var nodes = inwards ? node.outgoing : node.incoming; | ||
collections.forEach(nodes,(entry) => this._traverse(entry.value, inwards, seen, callback)); | ||
} | ||
private _traverse(node: Node<T>, inwards: boolean, seen: { [key: string]: boolean }, callback: (data: T) => void): void { | ||
var key = this._hashFn(node.data); | ||
if (collections.contains(seen, key)) { | ||
return; | ||
} | ||
seen[key] = true; | ||
callback(node.data); | ||
var nodes = inwards ? node.outgoing : node.incoming; | ||
collections.forEach(nodes,(entry) => this._traverse(entry.value, inwards, seen, callback)); | ||
} | ||
public inertEdge(from: T, to: T): void { | ||
var fromNode = this.lookupOrInsertNode(from), | ||
toNode = this.lookupOrInsertNode(to); | ||
public inertEdge(from: T, to: T): void { | ||
var fromNode = this.lookupOrInsertNode(from), | ||
toNode = this.lookupOrInsertNode(to); | ||
fromNode.outgoing[this._hashFn(to)] = toNode; | ||
toNode.incoming[this._hashFn(from)] = fromNode; | ||
} | ||
fromNode.outgoing[this._hashFn(to)] = toNode; | ||
toNode.incoming[this._hashFn(from)] = fromNode; | ||
} | ||
public removeNode(data: T): void { | ||
var key = this._hashFn(data); | ||
delete this._nodes[key]; | ||
collections.forEach(this._nodes,(entry) => { | ||
delete entry.value.outgoing[key]; | ||
delete entry.value.incoming[key]; | ||
}); | ||
} | ||
public removeNode(data: T): void { | ||
var key = this._hashFn(data); | ||
delete this._nodes[key]; | ||
collections.forEach(this._nodes,(entry) => { | ||
delete entry.value.outgoing[key]; | ||
delete entry.value.incoming[key]; | ||
}); | ||
} | ||
public lookupOrInsertNode(data: T): Node<T> { | ||
var key = this._hashFn(data), | ||
node = collections.lookup(this._nodes, key); | ||
public lookupOrInsertNode(data: T): Node<T> { | ||
var key = this._hashFn(data), | ||
node = collections.lookup(this._nodes, key); | ||
if (!node) { | ||
node = newNode(data); | ||
this._nodes[key] = node; | ||
} | ||
if (!node) { | ||
node = newNode(data); | ||
this._nodes[key] = node; | ||
} | ||
return node; | ||
} | ||
return node; | ||
} | ||
public lookup(data: T): Node<T> { | ||
return collections.lookup(this._nodes, this._hashFn(data)); | ||
} | ||
} | ||
public lookup(data: T): Node<T> { | ||
return collections.lookup(this._nodes, this._hashFn(data)); | ||
} | ||
} | ||
} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
3259094
27
61394
4
2
+ Addedclone@^0.2.0