Skip to content

Commit

Permalink
Add ability to easily get diagnostics.
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret committed May 2, 2017
1 parent 75d5acf commit 71a391c
Show file tree
Hide file tree
Showing 19 changed files with 405 additions and 37 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
/obj
/temp
/bin
/dist-cg
*.suo
*.csproj
*.csproj.user
Expand Down
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/node_modules
/coverage
/.vscode
/code-generation
/src
*.js.map
/obj
Expand Down
3 changes: 2 additions & 1 deletion docs/_layouts/default.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,13 @@ <h1 onclick="document.location.href = '{{ "/" | prepend: site.baseurl }}'" class
<ul>
<li class="{% if page.path == 'setup/index.md' %}active{% endif %}"><a href="{{ "/setup/index" | prepend: site.baseurl }}">Instantiating</a></li>
<li class="{% if page.path == 'setup/adding-sourcefiles.md' %}active{% endif %}"><a href="{{ "/setup/adding-sourcefiles" | prepend: site.baseurl }}">Adding SourceFiles</a></li>
<li class="{% if page.path == 'setup/diagnostics.md' %}active{% endif %}"><a href="{{ "/setup/diagnostics" | prepend: site.baseurl }}">Diagnostics</a></li>
</ul>
{% endif %}
</li>
<li class="nav-item{% if page.dir == '/navigation/' %} active{% endif %}">
<a class="nav-link" href="{{ "/navigation" | prepend: site.baseurl }}">Navigation</a>
{% if page.dir == '/navigation/' or page.dir == '/navigation/details/' %}
{% if page.dir == '/navigation/' %}
<ul>
<li class="{% if page.path == 'navigation/getting-sourcefiles.md' %}active{% endif %}"><a href="{{ "/navigation/getting-sourcefiles" | prepend: site.baseurl }}">Getting SourceFiles</a></li>
<li class="{% if page.path == 'navigation/example.md' %}active{% endif %}"><a href="{{ "/navigation/example" | prepend: site.baseurl }}">Example</a></li>
Expand Down
20 changes: 20 additions & 0 deletions docs/details/expressions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
title: Expressions
---

## Expression With Type Arguments

These are found in certain areas. For example `extends` and `implements` expressions.

### Getting expression

```typescript
// returns: ts.LeftHandSideExpression
const expression = expressionWithTypeArgs.getExpression(); // returns: Node
```

### Getting type arguments

```typescript
const typeArgs = expressionWithTypeArgs.getTypeArguments(); // returns: TypeNode[]
```
4 changes: 2 additions & 2 deletions docs/setup/adding-sourcefiles.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ You will need to populate the `ast` object with source files.
Specify as many file globs or file paths as you wish:

```typescript
ast.addSourceFiles("folder/**/*.ts");
ast.addSourceFiles("folder/**/*{.d.ts,.ts}");
ast.addSourceFiles("otherFolder/file.ts", "specifyAnotherFile.ts", "orAnotherGlob/**/*.ts");
```

Expand All @@ -33,4 +33,4 @@ const sourceFile = ast.addSourceFileFromText("path/for/myNewFile.ts", fileText);
sourceFile.save(); // or saveSync();
```

**Next step:** [Navigating the AST](../navigation/index)
**Next step:** [Diagnostics](diagnostics)
95 changes: 95 additions & 0 deletions docs/setup/diagnostics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
title: Diagnostics
---

## Diagnostics

Diagnostics (compile errors) can be retrieved on the AST or on source files by using the `.getDiagnostics()` method:

```typescript
const diagnostics = ast.getDiagnostics();
```

Calling it on a source file will only give you the diagnostics for that source file.

### Diagnostic

#### Message text

Returned message text could be a `string` or a `DiagnosticMessageChain`:

```typescript
const message = diagnostic.getMessageText();
```

#### Source file

Source file the diagnostic occurs in:

```typescript
const sourceFile = diagnostic.getSourceFile();
```

#### Start & length

Position in the file and length of the diagnostic:

```typescript
const start = diagnostic.getStart(); // returns: number
const length = diagnostic.getLength(); // returns: number
```

#### Category

Categories can be warnings, errors, or just messages.

```typescript
const category = diagnostic.getCategory(); // returns: ts.DiagnosticCategory
```

#### Code

This is the error code number:

```typescript
const code = diagnostic.getCode(); // returns: number
```

#### Source

```typescript
const source = diagnostic.getSource(); // returns: string | undefined
```

### DiagnosticMessageChain

A diagnostic message chain (DMC) will be returned by `diagnostic.getMessageText()` in certain scenarios.

According to the typescript compiler:

```
/**
* A linked list of formatted diagnostic messages to be used as part of a multiline message.
* It is built from the bottom up, leaving the head to be the "main" diagnostic.
* While it seems that DiagnosticMessageChain is structurally similar to DiagnosticMessage,
* the difference is that messages are all preformatted in DMC.
*/
```

The properties of a DMC are similar to a Diagnostic:

```typescript
const messageText = dmc.getMessageText(); // returns: string
const category = dmc.getCategory(); // returns: ts.DiagnosticCategory
const code = dmc.getCode(); // returns: number
```

#### Next DMC in linked list

Call `.getNext()`:

```typescript
const next = dmc.getNext(); // returns: DiagnosticMessageChain | undefined
```

**Next step:** [Navigating the AST](../navigation/index)
2 changes: 1 addition & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ gulp.task("test", ["pre-test"], function() {
});

gulp.task("tslint", function() {
return gulp.src(["./src/**/*.ts", "!./src/typings/**/*.d.ts"])
return gulp.src(["./src/**/*.ts", "!./src/typings/**/*.d.ts", "./code-generation/**/*.ts"])
.pipe(tslint({ formatter: "verbose" }))
.pipe(tslint.report());
});
Expand Down
16 changes: 13 additions & 3 deletions src/TsSimpleAst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,19 @@ export class TsSimpleAst {
}

/**
* Gets a type checker.
* Gets the compiler diagnostics.
* @param program - Optional program.
*/
getTypeChecker(): compiler.TypeChecker {
return this.compilerFactory.getTypeChecker();
getDiagnostics(program: compiler.Program = this.compilerFactory.getLanguageService().getProgram()): compiler.Diagnostic[] {
// todo: implement cancellation token
const compilerDiagnostics = ts.getPreEmitDiagnostics(program.getCompilerProgram());
return compilerDiagnostics.map(d => this.compilerFactory.getDiagnostic(d));
}

/**
* Gets a language service.
*/
getLanguageService(): compiler.LanguageService {
return this.compilerFactory.getLanguageService();
}
}
2 changes: 1 addition & 1 deletion src/compiler/base/ExportableNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export function ExportableNode<T extends Constructor<ExportableNodeExtensionType
if (thisSymbol.equals(defaultExportSymbol))
return true;

const aliasedSymbol = typeChecker.getAliasedSymbol(defaultExportSymbol);
const aliasedSymbol = defaultExportSymbol.getAliasedSymbol(typeChecker);
return thisSymbol.equals(aliasedSymbol);
}

Expand Down
8 changes: 8 additions & 0 deletions src/compiler/common/Symbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ export class Symbol {
return this.symbol.getName();
}

/**
* Gets the aliased symbol.
* @param typeChecker - Optional type checker.
*/
getAliasedSymbol(typeChecker: TypeChecker = this.factory.getTypeChecker()): Symbol | undefined {
return typeChecker.getAliasedSymbol(this);
}

/**
* Gets the symbol flags.
*/
Expand Down
12 changes: 11 additions & 1 deletion src/compiler/file/SourceFile.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as ts from "typescript";
import {Node, Symbol} from "./../common";
import {StatementedNode} from "./../statement";
import {TypeChecker} from "./../tools";
import {TypeChecker, Program, Diagnostic} from "./../tools";
import {FileUtils} from "./../../utils";

export const SourceFileBase = StatementedNode(Node);
Expand Down Expand Up @@ -66,6 +66,16 @@ export class SourceFile extends SourceFileBase<ts.SourceFile> {
return sourceFileSymbol.getExportByName("default");
}

/**
* Gets the compiler diagnostics.
* @param program - Optional program.
*/
getDiagnostics(program: Program = this.factory.getLanguageService().getProgram()): Diagnostic[] {
// todo: implement cancellation token
const compilerDiagnostics = ts.getPreEmitDiagnostics(program.getCompilerProgram(), this.getCompilerNode());
return compilerDiagnostics.map(d => this.factory.getDiagnostic(d));
}

/**
* Removes any "export default";
*/
Expand Down
4 changes: 3 additions & 1 deletion src/compiler/tools.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * from "./tools/LanguageService";
export * from "./tools/Diagnostic";
export * from "./tools/DiagnosticMessageChain";
export * from "./tools/LanguageService";
export * from "./tools/Program";
export * from "./tools/TypeChecker";
82 changes: 82 additions & 0 deletions src/compiler/tools/Diagnostic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import * as ts from "typescript";
import {CompilerFactory} from "./../../factories";
import {SourceFile} from "./../file";
import {DiagnosticMessageChain} from "./DiagnosticMessageChain";

/**
* Diagnostic.
*/
export class Diagnostic {
/** @internal */
readonly factory: CompilerFactory;
/** @internal */
diagnostic: ts.Diagnostic;

constructor(
factory: CompilerFactory,
diagnostic: ts.Diagnostic
) {
this.factory = factory;
this.diagnostic = diagnostic;
}

/**
* Gets the source file.
*/
getSourceFile() {
return this.factory.getSourceFile(this.diagnostic.file);
}

/**
* Gets the message text.
*/
getMessageText(): string | DiagnosticMessageChain {
const messageText = this.diagnostic.messageText;
if (typeof messageText === "string")
return messageText;

return this.factory.getDiagnosticMessageChain(messageText);
}

/**
* Gets the start.
*/
getStart() {
return this.diagnostic.start;
}

/**
* Gets the length.
*/
getLength() {
return this.diagnostic.length;
}

/**
* Gets the diagnostic category.
*/
getCategory(): ts.DiagnosticCategory {
return this.diagnostic.category;
}

/**
* Gets the code of the diagnostic.
*/
getCode() {
return this.diagnostic.code;
}

/**
* Gets the source.
*/
getSource() {
return this.diagnostic.source;
}

/**
* Gets the underlying compiler diagnostic.
*/
getCompilerDiagnostic(): ts.Diagnostic {
return this.diagnostic;
}
}
59 changes: 59 additions & 0 deletions src/compiler/tools/DiagnosticMessageChain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import * as ts from "typescript";
import {CompilerFactory} from "./../../factories";

/**
* Diagnostic message chain.
*/
export class DiagnosticMessageChain {
/** @internal */
readonly factory: CompilerFactory;
/** @internal */
diagnosticMessageChain: ts.DiagnosticMessageChain;

constructor(
factory: CompilerFactory,
diagnosticMessageChain: ts.DiagnosticMessageChain
) {
this.factory = factory;
this.diagnosticMessageChain = diagnosticMessageChain;
}

/**
* Gets the message text.
*/
getMessageText() {
return this.diagnosticMessageChain.messageText;
}

/**
* Gets th enext diagnostic message chain in the chain.
*/
getNext(): DiagnosticMessageChain | undefined {
const next = this.diagnosticMessageChain.next;
if (next == null)
return undefined;

return this.factory.getDiagnosticMessageChain(next);
}

/**
* Gets the code of the diagnostic message chain.
*/
getCode() {
return this.diagnosticMessageChain.code;
}

/**
* Gets the category of the diagnostic message chain.
*/
getCategory(): ts.DiagnosticCategory {
return this.diagnosticMessageChain.category;
}

/**
* Gets the underlying compiler object.
*/
getCompilerDiagnosticMessageChain(): ts.DiagnosticMessageChain {
return this.diagnosticMessageChain;
}
}
Loading

0 comments on commit 71a391c

Please sign in to comment.