Merge pull request #4 from ezolenko/error_categories

Error categories
This commit is contained in:
Eugene Zolenko 2017-03-04 18:57:13 -07:00 committed by GitHub
commit 08c76cb75a
8 changed files with 428 additions and 136 deletions

View File

@ -1,4 +1,5 @@
{
"editor.tabSize": 4,
"editor.useTabStops": true
"editor.useTabStops": true,
"editor.dragAndDrop": true
}

View File

@ -33,18 +33,35 @@ Following compiler options are forced though:
* `noResolve`: false
Plugin takes following options:
* `check`: true
- set to false to avoid doing any diagnostic checks on the code
Set to false to avoid doing any diagnostic checks on the code.
* `verbosity`: 2
- goes up to 3
Goes up to 3.
* `clean`: false
- set to true for clean build (wipes out cache)
Set to true for clean build (wipes out cache on every build).
* `cacheRoot`: ".rts2_cache"
- path to cache
Path to cache.
* `include`: `[ "*.ts+(|x)", "**/*.ts+(|x)" ]`
- passes all .ts files through typescript compiler.
Passes all .ts files through typescript compiler.
* `exclude`: `[ "*.d.ts", "**/*.d.ts" ]`
- but not types
But excludes types.
* `abortOnError`: true
Bail out on first syntactic error. Im most cases setting this to false will result in exception in rollup itself.
### TypeScript version
This plugin currently requires TypeScript 2.0+.

View File

@ -71,6 +71,40 @@ var ConsoleContext = (function () {
return ConsoleContext;
}());
var RollupContext = (function () {
function RollupContext(verbosity, bail, context, prefix) {
if (prefix === void 0) { prefix = ""; }
this.verbosity = verbosity;
this.bail = bail;
this.context = context;
this.prefix = prefix;
}
RollupContext.prototype.warn = function (message) {
if (this.verbosity < VerbosityLevel.Warning)
return;
this.context.warn("" + this.prefix + message);
};
RollupContext.prototype.error = function (message) {
if (this.verbosity < VerbosityLevel.Error)
return;
if (this.bail)
this.context.error("" + this.prefix + message);
else
this.context.warn("" + this.prefix + message);
};
RollupContext.prototype.info = function (message) {
if (this.verbosity < VerbosityLevel.Info)
return;
this.context.warn("" + this.prefix + message);
};
RollupContext.prototype.debug = function (message) {
if (this.verbosity < VerbosityLevel.Debug)
return;
this.context.warn("" + this.prefix + message);
};
return RollupContext;
}());
var LanguageServiceHost = (function () {
function LanguageServiceHost(parsedConfig) {
this.parsedConfig = parsedConfig;
@ -175,15 +209,33 @@ var RollingCache = (function () {
return RollingCache;
}());
function convertDiagnostic(data) {
return _.map(data, function (diagnostic) {
var entry = {
flatMessage: ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"),
category: diagnostic.category,
};
if (diagnostic.file) {
var _a = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start), line = _a.line, character = _a.character;
entry.fileLine = diagnostic.file.fileName + " (" + (line + 1) + "," + (character + 1) + ")";
}
return entry;
});
}
var Cache = (function () {
function Cache(host, cache, options, rootFilenames, context) {
var _this = this;
this.host = host;
this.options = options;
this.context = context;
this.cacheVersion = "1";
this.cacheVersion = "2";
this.ambientTypesDirty = false;
this.cacheDir = cache + "/" + hash.sha1({ version: this.cacheVersion, rootFilenames: rootFilenames, options: this.options });
this.cacheDir = cache + "/" + hash.sha1({
version: this.cacheVersion,
rootFilenames: rootFilenames,
options: this.options,
tsVersion: ts.version,
});
this.dependencyTree = new graph.Graph({ directed: true });
this.dependencyTree.setDefaultNodeLabel(function (_node) { return { dirty: false }; });
this.ambientTypes = _.filter(rootFilenames, function (file) { return _.endsWith(file, ".d.ts"); })
@ -221,7 +273,8 @@ var Cache = (function () {
};
Cache.prototype.diagnosticsDone = function () {
this.codeCache.roll();
this.diagnosticsCache.roll();
this.semanticDiagnosticsCache.roll();
this.syntacticDiagnosticsCache.roll();
this.typesCache.roll();
};
Cache.prototype.getCompiled = function (id, snapshot, transform) {
@ -238,24 +291,31 @@ var Cache = (function () {
this.codeCache.write(name, data);
return data;
};
Cache.prototype.getDiagnostics = function (id, snapshot, check) {
Cache.prototype.getSyntacticDiagnostics = function (id, snapshot, check) {
return this.getDiagnostics(this.syntacticDiagnosticsCache, id, snapshot, check);
};
Cache.prototype.getSemanticDiagnostics = function (id, snapshot, check) {
return this.getDiagnostics(this.semanticDiagnosticsCache, id, snapshot, check);
};
Cache.prototype.getDiagnostics = function (cache, id, snapshot, check) {
var name = this.makeName(id, snapshot);
if (!this.diagnosticsCache.exists(name) || this.isDirty(id, snapshot, true)) {
if (!cache.exists(name) || this.isDirty(id, snapshot, true)) {
this.context.debug("fresh diagnostics for: " + id);
var data_2 = this.convert(check());
this.diagnosticsCache.write(name, data_2);
var data_2 = convertDiagnostic(check());
cache.write(name, data_2);
this.markAsDirty(id, snapshot);
return data_2;
}
this.context.debug("old diagnostics for: " + id);
var data = this.diagnosticsCache.read(name);
this.diagnosticsCache.write(name, data);
var data = cache.read(name);
cache.write(name, data);
return data;
};
Cache.prototype.init = function () {
this.codeCache = new RollingCache(this.cacheDir + "/code", true);
this.typesCache = new RollingCache(this.cacheDir + "/types", false);
this.diagnosticsCache = new RollingCache(this.cacheDir + "/diagnostics", false);
this.syntacticDiagnosticsCache = new RollingCache(this.cacheDir + "/syntacticDiagnostics", false);
this.semanticDiagnosticsCache = new RollingCache(this.cacheDir + "/semanticDiagnostics", false);
};
Cache.prototype.markAsDirty = function (id, _snapshot) {
this.context.debug("changed: " + id);
@ -286,18 +346,6 @@ var Cache = (function () {
var data = snapshot.getText(0, snapshot.getLength());
return hash.sha1({ data: data, id: id });
};
Cache.prototype.convert = function (data) {
return _.map(data, function (diagnostic) {
var entry = {
flatMessage: ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"),
};
if (diagnostic.file) {
var _a = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start), line = _a.line, character = _a.character;
entry.fileLine = diagnostic.file.fileName + " (" + (line + 1) + "," + (character + 1) + ")";
}
return entry;
});
};
return Cache;
}());
@ -352,10 +400,27 @@ function parseTsConfig() {
}
function printDiagnostics(context, diagnostics) {
_.each(diagnostics, function (diagnostic) {
var print;
var color;
switch (diagnostic.category) {
case ts.DiagnosticCategory.Message:
print = context.info;
color = colors.white;
break;
case ts.DiagnosticCategory.Error:
print = context.error;
color = colors.red;
break;
case ts.DiagnosticCategory.Warning:
default:
print = context.warn;
color = colors.yellow;
break;
}
if (diagnostic.fileLine)
context.warn(diagnostic.fileLine + ": " + colors.yellow(diagnostic.flatMessage));
print.call(context, [diagnostic.fileLine + ": " + color(diagnostic.flatMessage)]);
else
context.warn(colors.yellow(diagnostic.flatMessage));
print.call(context, [color(diagnostic.flatMessage)]);
});
}
@ -368,6 +433,7 @@ function typescript(options) {
cacheRoot: process.cwd() + "/.rts2_cache",
include: ["*.ts+(|x)", "**/*.ts+(|x)"],
exclude: ["*.d.ts", "**/*.d.ts"],
abortOnError: true,
});
var filter$$1 = createFilter(options.include, options.exclude);
var parsedConfig = parseTsConfig();
@ -403,17 +469,21 @@ function typescript(options) {
var _this = this;
if (!filter$$1(id))
return undefined;
var contextWrapper = new RollupContext(options.verbosity, options.abortOnError, this, "rollup-plugin-typescript2: ");
contextWrapper.debug(id);
var snapshot = servicesHost.setSnapshot(id, code);
// getting compiled file from cache of from ts
var result = cache.getCompiled(id, snapshot, function () {
var output = services.getEmitOutput(id);
if (output.emitSkipped) {
var diagnostics = cache.getDiagnostics(id, snapshot, function () {
return services
.getCompilerOptionsDiagnostics()
.concat(services.getSyntacticDiagnostics(id))
.concat(services.getSemanticDiagnostics(id));
});
printDiagnostics(_this, diagnostics);
if (options.check) {
var diagnostics = cache.getSyntacticDiagnostics(id, snapshot, function () {
return services.getSyntacticDiagnostics(id);
});
contextWrapper.debug("printDiagnostics");
printDiagnostics(contextWrapper, diagnostics);
}
// if no output was generated, aborting compilation
_this.error(colors.red("failed to transpile " + id));
}
var transpiled = _.find(output.outputFiles, function (entry) { return _.endsWith(entry.name, ".js"); });
@ -423,11 +493,26 @@ function typescript(options) {
map: map$$1 ? JSON.parse(map$$1.text) : { mappings: "" },
};
});
// printing syntactic errors
if (options.check) {
var diagnostics = cache.getSyntacticDiagnostics(id, snapshot, function () {
return services.getSyntacticDiagnostics(id);
});
contextWrapper.debug("printDiagnostics");
printDiagnostics(contextWrapper, diagnostics);
}
return result;
},
intro: function () {
context.debug("intro");
// printing compiler option errors
if (options.check)
printDiagnostics(context, convertDiagnostic(services.getCompilerOptionsDiagnostics()));
},
outro: function () {
context.debug("outro");
cache.compileDone();
// printing semantic errors
if (options.check) {
cache.walkTree(function (id) {
var snapshot = servicesHost.getScriptSnapshot(id);
@ -435,11 +520,8 @@ function typescript(options) {
context.error(colors.red("failed lo load snapshot for " + id));
return;
}
var diagnostics = cache.getDiagnostics(id, snapshot, function () {
return services
.getCompilerOptionsDiagnostics()
.concat(services.getSyntacticDiagnostics(id))
.concat(services.getSemanticDiagnostics(id));
var diagnostics = cache.getSemanticDiagnostics(id, snapshot, function () {
return services.getSemanticDiagnostics(id);
});
printDiagnostics(context, diagnostics);
});

View File

@ -1,7 +1,7 @@
/* eslint-disable */
import { emptyDirSync, ensureFile, ensureFileSync, existsSync, move, readFileSync, readJsonSync, readdirSync, remove, writeJson, writeJsonSync } from 'fs-extra';
import * as fs from 'fs-extra';
import { ModuleKind, ScriptSnapshot, createDocumentRegistry, createLanguageService, flattenDiagnosticMessageText, getDefaultLibFilePath, nodeModuleNameResolver, parseConfigFileTextToJson, parseJsonConfigFileContent, sys } from 'typescript';
import { DiagnosticCategory, ModuleKind, ScriptSnapshot, createDocumentRegistry, createLanguageService, flattenDiagnosticMessageText, getDefaultLibFilePath, nodeModuleNameResolver, parseConfigFileTextToJson, parseJsonConfigFileContent, sys, version } from 'typescript';
import * as ts from 'typescript';
import { defaults, each, endsWith, filter, find, has, isEqual, map, some } from 'lodash';
import * as _ from 'lodash';
@ -11,7 +11,7 @@ import { sha1 } from 'object-hash';
import * as hash from 'object-hash';
import { dirname, sep } from 'path';
import * as path from 'path';
import { red, yellow } from 'colors/safe';
import { red, white, yellow } from 'colors/safe';
import * as colors from 'colors/safe';
/*! *****************************************************************************
@ -76,6 +76,40 @@ var ConsoleContext = (function () {
return ConsoleContext;
}());
var RollupContext = (function () {
function RollupContext(verbosity, bail, context, prefix) {
if (prefix === void 0) { prefix = ""; }
this.verbosity = verbosity;
this.bail = bail;
this.context = context;
this.prefix = prefix;
}
RollupContext.prototype.warn = function (message) {
if (this.verbosity < VerbosityLevel.Warning)
return;
this.context.warn("" + this.prefix + message);
};
RollupContext.prototype.error = function (message) {
if (this.verbosity < VerbosityLevel.Error)
return;
if (this.bail)
this.context.error("" + this.prefix + message);
else
this.context.warn("" + this.prefix + message);
};
RollupContext.prototype.info = function (message) {
if (this.verbosity < VerbosityLevel.Info)
return;
this.context.warn("" + this.prefix + message);
};
RollupContext.prototype.debug = function (message) {
if (this.verbosity < VerbosityLevel.Debug)
return;
this.context.warn("" + this.prefix + message);
};
return RollupContext;
}());
var LanguageServiceHost = (function () {
function LanguageServiceHost(parsedConfig) {
this.parsedConfig = parsedConfig;
@ -180,15 +214,33 @@ var RollingCache = (function () {
return RollingCache;
}());
function convertDiagnostic(data) {
return map(data, function (diagnostic) {
var entry = {
flatMessage: flattenDiagnosticMessageText(diagnostic.messageText, "\n"),
category: diagnostic.category,
};
if (diagnostic.file) {
var _a = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start), line = _a.line, character = _a.character;
entry.fileLine = diagnostic.file.fileName + " (" + (line + 1) + "," + (character + 1) + ")";
}
return entry;
});
}
var Cache = (function () {
function Cache(host, cache, options, rootFilenames, context) {
var _this = this;
this.host = host;
this.options = options;
this.context = context;
this.cacheVersion = "1";
this.cacheVersion = "2";
this.ambientTypesDirty = false;
this.cacheDir = cache + "/" + sha1({ version: this.cacheVersion, rootFilenames: rootFilenames, options: this.options });
this.cacheDir = cache + "/" + sha1({
version: this.cacheVersion,
rootFilenames: rootFilenames,
options: this.options,
tsVersion: version,
});
this.dependencyTree = new Graph({ directed: true });
this.dependencyTree.setDefaultNodeLabel(function (_node) { return { dirty: false }; });
this.ambientTypes = filter(rootFilenames, function (file) { return endsWith(file, ".d.ts"); })
@ -226,7 +278,8 @@ var Cache = (function () {
};
Cache.prototype.diagnosticsDone = function () {
this.codeCache.roll();
this.diagnosticsCache.roll();
this.semanticDiagnosticsCache.roll();
this.syntacticDiagnosticsCache.roll();
this.typesCache.roll();
};
Cache.prototype.getCompiled = function (id, snapshot, transform) {
@ -243,24 +296,31 @@ var Cache = (function () {
this.codeCache.write(name, data);
return data;
};
Cache.prototype.getDiagnostics = function (id, snapshot, check) {
Cache.prototype.getSyntacticDiagnostics = function (id, snapshot, check) {
return this.getDiagnostics(this.syntacticDiagnosticsCache, id, snapshot, check);
};
Cache.prototype.getSemanticDiagnostics = function (id, snapshot, check) {
return this.getDiagnostics(this.semanticDiagnosticsCache, id, snapshot, check);
};
Cache.prototype.getDiagnostics = function (cache, id, snapshot, check) {
var name = this.makeName(id, snapshot);
if (!this.diagnosticsCache.exists(name) || this.isDirty(id, snapshot, true)) {
if (!cache.exists(name) || this.isDirty(id, snapshot, true)) {
this.context.debug("fresh diagnostics for: " + id);
var data_2 = this.convert(check());
this.diagnosticsCache.write(name, data_2);
var data_2 = convertDiagnostic(check());
cache.write(name, data_2);
this.markAsDirty(id, snapshot);
return data_2;
}
this.context.debug("old diagnostics for: " + id);
var data = this.diagnosticsCache.read(name);
this.diagnosticsCache.write(name, data);
var data = cache.read(name);
cache.write(name, data);
return data;
};
Cache.prototype.init = function () {
this.codeCache = new RollingCache(this.cacheDir + "/code", true);
this.typesCache = new RollingCache(this.cacheDir + "/types", false);
this.diagnosticsCache = new RollingCache(this.cacheDir + "/diagnostics", false);
this.syntacticDiagnosticsCache = new RollingCache(this.cacheDir + "/syntacticDiagnostics", false);
this.semanticDiagnosticsCache = new RollingCache(this.cacheDir + "/semanticDiagnostics", false);
};
Cache.prototype.markAsDirty = function (id, _snapshot) {
this.context.debug("changed: " + id);
@ -291,18 +351,6 @@ var Cache = (function () {
var data = snapshot.getText(0, snapshot.getLength());
return sha1({ data: data, id: id });
};
Cache.prototype.convert = function (data) {
return map(data, function (diagnostic) {
var entry = {
flatMessage: flattenDiagnosticMessageText(diagnostic.messageText, "\n"),
};
if (diagnostic.file) {
var _a = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start), line = _a.line, character = _a.character;
entry.fileLine = diagnostic.file.fileName + " (" + (line + 1) + "," + (character + 1) + ")";
}
return entry;
});
};
return Cache;
}());
@ -357,10 +405,27 @@ function parseTsConfig() {
}
function printDiagnostics(context, diagnostics) {
each(diagnostics, function (diagnostic) {
var print;
var color;
switch (diagnostic.category) {
case DiagnosticCategory.Message:
print = context.info;
color = white;
break;
case DiagnosticCategory.Error:
print = context.error;
color = red;
break;
case DiagnosticCategory.Warning:
default:
print = context.warn;
color = yellow;
break;
}
if (diagnostic.fileLine)
context.warn(diagnostic.fileLine + ": " + yellow(diagnostic.flatMessage));
print.call(context, [diagnostic.fileLine + ": " + color(diagnostic.flatMessage)]);
else
context.warn(yellow(diagnostic.flatMessage));
print.call(context, [color(diagnostic.flatMessage)]);
});
}
@ -373,6 +438,7 @@ function typescript(options) {
cacheRoot: process.cwd() + "/.rts2_cache",
include: ["*.ts+(|x)", "**/*.ts+(|x)"],
exclude: ["*.d.ts", "**/*.d.ts"],
abortOnError: true,
});
var filter$$1 = createFilter(options.include, options.exclude);
var parsedConfig = parseTsConfig();
@ -408,17 +474,21 @@ function typescript(options) {
var _this = this;
if (!filter$$1(id))
return undefined;
var contextWrapper = new RollupContext(options.verbosity, options.abortOnError, this, "rollup-plugin-typescript2: ");
contextWrapper.debug(id);
var snapshot = servicesHost.setSnapshot(id, code);
// getting compiled file from cache of from ts
var result = cache.getCompiled(id, snapshot, function () {
var output = services.getEmitOutput(id);
if (output.emitSkipped) {
var diagnostics = cache.getDiagnostics(id, snapshot, function () {
return services
.getCompilerOptionsDiagnostics()
.concat(services.getSyntacticDiagnostics(id))
.concat(services.getSemanticDiagnostics(id));
});
printDiagnostics(_this, diagnostics);
if (options.check) {
var diagnostics = cache.getSyntacticDiagnostics(id, snapshot, function () {
return services.getSyntacticDiagnostics(id);
});
contextWrapper.debug("printDiagnostics");
printDiagnostics(contextWrapper, diagnostics);
}
// if no output was generated, aborting compilation
_this.error(red("failed to transpile " + id));
}
var transpiled = find(output.outputFiles, function (entry) { return endsWith(entry.name, ".js"); });
@ -428,11 +498,26 @@ function typescript(options) {
map: map$$1 ? JSON.parse(map$$1.text) : { mappings: "" },
};
});
// printing syntactic errors
if (options.check) {
var diagnostics = cache.getSyntacticDiagnostics(id, snapshot, function () {
return services.getSyntacticDiagnostics(id);
});
contextWrapper.debug("printDiagnostics");
printDiagnostics(contextWrapper, diagnostics);
}
return result;
},
intro: function () {
context.debug("intro");
// printing compiler option errors
if (options.check)
printDiagnostics(context, convertDiagnostic(services.getCompilerOptionsDiagnostics()));
},
outro: function () {
context.debug("outro");
cache.compileDone();
// printing semantic errors
if (options.check) {
cache.walkTree(function (id) {
var snapshot = servicesHost.getScriptSnapshot(id);
@ -440,11 +525,8 @@ function typescript(options) {
context.error(red("failed lo load snapshot for " + id));
return;
}
var diagnostics = cache.getDiagnostics(id, snapshot, function () {
return services
.getCompilerOptionsDiagnostics()
.concat(services.getSyntacticDiagnostics(id))
.concat(services.getSemanticDiagnostics(id));
var diagnostics = cache.getSemanticDiagnostics(id, snapshot, function () {
return services.getSemanticDiagnostics(id);
});
printDiagnostics(context, diagnostics);
});

View File

@ -1,6 +1,6 @@
{
"name": "rollup-plugin-typescript2",
"version": "0.1.2",
"version": "0.2.0",
"description": "Seamless integration between Rollup and TypeScript. Now with errors.",
"main": "dist/rollup-plugin-typescript2.cjs.js",
"module": "dist/rollup-plugin-typescript2.es.js",
@ -29,14 +29,14 @@
"lodash": "^4.17.4",
"object-hash": "^1.1.5",
"rollup-pluginutils": "^2.0.1",
"tslib": "^1.5.0"
"tslib": "^1.6.0"
},
"peerDependencies": {
"typescript": "^2.0",
"tslib": "^1.5.0"
},
"devDependencies": {
"rollup-plugin-typescript2": "^0.1.0",
"rollup-plugin-typescript2": "^0.1.2",
"@types/colors": "^1.1.1",
"@types/fs-extra": "0.0.37",
"@types/graphlib": "^2.1.3",
@ -45,8 +45,8 @@
"@types/object-hash": "^0.5.28",
"rimraf": "^2.5.4",
"rollup": "^0.41.4",
"tslint": "^4.4.2",
"typescript": "^2.1.5"
"tslint": "^4.5.1",
"typescript": "^2.2.1"
},
"repository": {
"type": "git",

View File

@ -21,6 +21,7 @@ export interface IDiagnostics
{
flatMessage: string;
fileLine?: string;
category: ts.DiagnosticCategory;
}
interface ITypeSnapshot
@ -29,20 +30,46 @@ interface ITypeSnapshot
snapshot: ts.IScriptSnapshot | undefined;
}
export function convertDiagnostic(data: ts.Diagnostic[]): IDiagnostics[]
{
return _.map(data, (diagnostic) =>
{
let entry: IDiagnostics =
{
flatMessage: ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"),
category: diagnostic.category,
};
if (diagnostic.file)
{
let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
entry.fileLine = `${diagnostic.file.fileName} (${line + 1},${character + 1})`;
}
return entry;
});
}
export class Cache
{
private cacheVersion = "1";
private cacheVersion = "2";
private dependencyTree: graph.Graph;
private ambientTypes: ITypeSnapshot[];
private ambientTypesDirty = false;
private cacheDir: string;
private codeCache: RollingCache<ICode | undefined>;
private typesCache: RollingCache<string>;
private diagnosticsCache: RollingCache<IDiagnostics[]>;
private semanticDiagnosticsCache: RollingCache<IDiagnostics[]>;
private syntacticDiagnosticsCache: RollingCache<IDiagnostics[]>;
constructor(private host: ts.LanguageServiceHost, cache: string, private options: ts.CompilerOptions, rootFilenames: string[], private context: IContext)
{
this.cacheDir = `${cache}/${hash.sha1({ version: this.cacheVersion, rootFilenames, options: this.options })}`;
this.cacheDir = `${cache}/${hash.sha1({
version: this.cacheVersion,
rootFilenames,
options: this.options,
tsVersion : ts.version,
})}`;
this.dependencyTree = new graph.Graph({ directed: true });
this.dependencyTree.setDefaultNodeLabel((_node: string) => { return { dirty: false }; });
@ -102,7 +129,8 @@ export class Cache
public diagnosticsDone()
{
this.codeCache.roll();
this.diagnosticsCache.roll();
this.semanticDiagnosticsCache.roll();
this.syntacticDiagnosticsCache.roll();
this.typesCache.roll();
}
@ -127,24 +155,34 @@ export class Cache
return data;
}
public getDiagnostics(id: string, snapshot: ts.IScriptSnapshot, check: () => ts.Diagnostic[]): IDiagnostics[]
public getSyntacticDiagnostics(id: string, snapshot: ts.IScriptSnapshot, check: () => ts.Diagnostic[]): IDiagnostics[]
{
return this.getDiagnostics(this.syntacticDiagnosticsCache, id, snapshot, check);
}
public getSemanticDiagnostics(id: string, snapshot: ts.IScriptSnapshot, check: () => ts.Diagnostic[]): IDiagnostics[]
{
return this.getDiagnostics(this.semanticDiagnosticsCache, id, snapshot, check);
}
private getDiagnostics(cache: RollingCache<IDiagnostics[]>, id: string, snapshot: ts.IScriptSnapshot, check: () => ts.Diagnostic[]): IDiagnostics[]
{
let name = this.makeName(id, snapshot);
if (!this.diagnosticsCache.exists(name) || this.isDirty(id, snapshot, true))
if (!cache.exists(name) || this.isDirty(id, snapshot, true))
{
this.context.debug(`fresh diagnostics for: ${id}`);
let data = this.convert(check());
this.diagnosticsCache.write(name, data);
let data = convertDiagnostic(check());
cache.write(name, data);
this.markAsDirty(id, snapshot);
return data;
}
this.context.debug(`old diagnostics for: ${id}`);
let data = this.diagnosticsCache.read(name);
this.diagnosticsCache.write(name, data);
let data = cache.read(name);
cache.write(name, data);
return data;
}
@ -152,7 +190,8 @@ export class Cache
{
this.codeCache = new RollingCache<ICode>(`${this.cacheDir}/code`, true);
this.typesCache = new RollingCache<string>(`${this.cacheDir}/types`, false);
this.diagnosticsCache = new RollingCache<IDiagnostics[]>(`${this.cacheDir}/diagnostics`, false);
this.syntacticDiagnosticsCache = new RollingCache<IDiagnostics[]>(`${this.cacheDir}/syntacticDiagnostics`, false);
this.semanticDiagnosticsCache = new RollingCache<IDiagnostics[]>(`${this.cacheDir}/semanticDiagnostics`, false);
}
private markAsDirty(id: string, _snapshot: ts.IScriptSnapshot): void
@ -197,23 +236,4 @@ export class Cache
let data = snapshot.getText(0, snapshot.getLength());
return hash.sha1({ data, id });
}
private convert(data: ts.Diagnostic[]): IDiagnostics[]
{
return _.map(data, (diagnostic) =>
{
let entry: IDiagnostics =
{
flatMessage: ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"),
};
if (diagnostic.file)
{
let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
entry.fileLine = `${diagnostic.file.fileName} (${line + 1},${character + 1})`;
}
return entry;
});
}
}

View File

@ -1,6 +1,7 @@
import { RollupContext } from "./rollupcontext";
import { IContext, ConsoleContext, IRollupContext, VerbosityLevel } from "./context";
import { LanguageServiceHost } from "./host";
import { Cache, ICode, IDiagnostics } from "./cache";
import { Cache, convertDiagnostic, ICode, IDiagnostics } from "./cache";
import * as ts from "typescript";
import * as fs from "fs-extra";
import * as path from "path";
@ -72,14 +73,33 @@ function parseTsConfig()
return configParseResult;
}
function printDiagnostics(context: IContext | IRollupContext, diagnostics: IDiagnostics[])
function printDiagnostics(context: IContext, diagnostics: IDiagnostics[])
{
_.each(diagnostics, (diagnostic) =>
{
let print;
let color;
switch (diagnostic.category)
{
case ts.DiagnosticCategory.Message:
print = context.info;
color = colors.white;
break;
case ts.DiagnosticCategory.Error:
print = context.error;
color = colors.red;
break;
case ts.DiagnosticCategory.Warning:
default:
print = context.warn;
color = colors.yellow;
break;
}
if (diagnostic.fileLine)
context.warn(`${diagnostic.fileLine}: ${colors.yellow(diagnostic.flatMessage)}`);
print.call(context, [`${diagnostic.fileLine}: ${color(diagnostic.flatMessage)}`]);
else
context.warn(colors.yellow(diagnostic.flatMessage));
print.call(context, [color(diagnostic.flatMessage)]);
});
};
@ -91,6 +111,7 @@ interface IOptions
verbosity: number;
clean: boolean;
cacheRoot: string;
abortOnError: boolean;
}
export default function typescript (options: IOptions)
@ -105,11 +126,12 @@ export default function typescript (options: IOptions)
cacheRoot: `${process.cwd()}/.rts2_cache`,
include: [ "*.ts+(|x)", "**/*.ts+(|x)" ],
exclude: [ "*.d.ts", "**/*.d.ts" ],
abortOnError: true,
});
const filter = createFilter(options.include, options.exclude);
let parsedConfig = parseTsConfig();
const parsedConfig = parseTsConfig();
const servicesHost = new LanguageServiceHost(parsedConfig);
@ -163,26 +185,35 @@ export default function typescript (options: IOptions)
if (!filter(id))
return undefined;
const contextWrapper = new RollupContext(options.verbosity, options.abortOnError, this, "rollup-plugin-typescript2: ");
contextWrapper.debug(id);
const snapshot = servicesHost.setSnapshot(id, code);
let result = cache.getCompiled(id, snapshot, () =>
// getting compiled file from cache of from ts
const result = cache.getCompiled(id, snapshot, () =>
{
const output = services.getEmitOutput(id);
if (output.emitSkipped)
{
const diagnostics = cache.getDiagnostics(id, snapshot, () =>
if (options.check)
{
return services
.getCompilerOptionsDiagnostics()
.concat(services.getSyntacticDiagnostics(id))
.concat(services.getSemanticDiagnostics(id));
});
printDiagnostics(this, diagnostics);
const diagnostics = cache.getSyntacticDiagnostics(id, snapshot, () =>
{
return services.getSyntacticDiagnostics(id);
});
contextWrapper.debug("printDiagnostics");
printDiagnostics(contextWrapper, diagnostics);
}
// if no output was generated, aborting compilation
this.error(colors.red(`failed to transpile ${id}`));
}
const transpiled = _.find(output.outputFiles, (entry: ts.OutputFile) => _.endsWith(entry.name, ".js") );
const map = _.find(output.outputFiles, (entry: ts.OutputFile) => _.endsWith(entry.name, ".map") );
const transpiled = _.find(output.outputFiles, (entry) => _.endsWith(entry.name, ".js") );
const map = _.find(output.outputFiles, (entry) => _.endsWith(entry.name, ".map") );
return {
code: transpiled ? transpiled.text : undefined,
@ -190,14 +221,36 @@ export default function typescript (options: IOptions)
};
});
// printing syntactic errors
if (options.check)
{
const diagnostics = cache.getSyntacticDiagnostics(id, snapshot, () =>
{
return services.getSyntacticDiagnostics(id);
});
contextWrapper.debug("printDiagnostics");
printDiagnostics(contextWrapper, diagnostics);
}
return result;
},
intro(): void
{
context.debug("intro");
// printing compiler option errors
if (options.check)
printDiagnostics(context, convertDiagnostic(services.getCompilerOptionsDiagnostics()));
},
outro(): void
{
context.debug("outro");
cache.compileDone();
// printing semantic errors
if (options.check)
{
cache.walkTree((id: string) =>
@ -210,12 +263,9 @@ export default function typescript (options: IOptions)
return;
}
const diagnostics = cache.getDiagnostics(id, snapshot, () =>
const diagnostics = cache.getSemanticDiagnostics(id, snapshot, () =>
{
return services
.getCompilerOptionsDiagnostics()
.concat(services.getSyntacticDiagnostics(id))
.concat(services.getSemanticDiagnostics(id));
return services.getSemanticDiagnostics(id);
});
printDiagnostics(context, diagnostics);

40
src/rollupcontext.ts Normal file
View File

@ -0,0 +1,40 @@
import { IContext, IRollupContext, VerbosityLevel } from "./context";
export class RollupContext implements IContext
{
constructor(private verbosity: VerbosityLevel, private bail: boolean, private context: IRollupContext, private prefix: string = "")
{
}
public warn(message: string): void
{
if (this.verbosity < VerbosityLevel.Warning)
return;
this.context.warn(`${this.prefix}${message}`);
}
public error(message: string): void
{
if (this.verbosity < VerbosityLevel.Error)
return;
if (this.bail)
this.context.error(`${this.prefix}${message}`);
else
this.context.warn(`${this.prefix}${message}`);
}
public info(message: string): void
{
if (this.verbosity < VerbosityLevel.Info)
return;
this.context.warn(`${this.prefix}${message}`);
}
public debug(message: string): void
{
if (this.verbosity < VerbosityLevel.Debug)
return;
this.context.warn(`${this.prefix}${message}`);
}
}