Skip to content

Commit bff6b05

Browse files
committed
Merge branch 'extensibility-model' into language-service-extensions
2 parents a03e465 + 4eee39d commit bff6b05

File tree

4 files changed

+41
-30
lines changed

4 files changed

+41
-30
lines changed

src/compiler/program.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,13 +1605,12 @@ namespace ts {
16051605
function visitNode(node: Node) {
16061606
let oneAccepted = false;
16071607
const oldParent = parent;
1608-
const needsReset: boolean[] = new Array(initializedLints.length);
1608+
const needsReset: Map<boolean> = {};
16091609
for (let i = 0; i < initializedLints.length; i++) {
16101610
if (initializedLints[i].accepted) {
16111611
activeLint = initializedLints[i];
1612-
activeLint.accepted = false;
16131612
node.parent = parent;
1614-
activeLint.walker.visit(node, accept, error);
1613+
activeLint.walker.visit(node, stop, error);
16151614
if (activeLint.accepted) {
16161615
oneAccepted = true;
16171616
}
@@ -1633,12 +1632,23 @@ namespace ts {
16331632
}
16341633
}
16351634

1636-
function accept() {
1637-
activeLint.accepted = true;
1635+
function stop() {
1636+
activeLint.accepted = false;
16381637
}
16391638

1640-
function error(err: string, node: Node) {
1641-
diagnostics.push(createExtensionDiagnosticForNode(node, activeLint.name, err));
1639+
function error(err: string): void;
1640+
function error(err: string, node: Node): void;
1641+
function error(err: string, start: number, length: number): void;
1642+
function error(err: string, nodeOrStart?: Node | number, length?: number): void {
1643+
if (typeof nodeOrStart === "undefined") {
1644+
diagnostics.push(createExtensionDiagnostic(activeLint.name, err, sourceFile));
1645+
}
1646+
else if (typeof nodeOrStart === "number") {
1647+
diagnostics.push(createExtensionDiagnostic(activeLint.name, err, sourceFile, nodeOrStart, length));
1648+
}
1649+
else {
1650+
diagnostics.push(createExtensionDiagnosticForNode(nodeOrStart, activeLint.name, err));
1651+
}
16421652
}
16431653
}
16441654

src/compiler/types.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2901,15 +2901,19 @@ namespace ts {
29012901
failedLookupLocations: string[];
29022902
}
29032903

2904-
export type LintErrorMethod = (err: string, span: Node) => void;
2905-
export type LintAcceptMethod = () => void;
2904+
export type LintErrorMethod = {
2905+
(err: string): void;
2906+
(err: string, span: Node): void;
2907+
(err: string, start: number, length: number): void;
2908+
};
2909+
export type LintStopMethod = () => void;
29062910

29072911
/*
2908-
* Walkers call accept to decend into the node's children
2912+
* Walkers call stop to halt recursion into the node's children
29092913
* Walkers call error to add errors to the output.
29102914
*/
29112915
export interface LintWalker {
2912-
visit(node: Node, accept: LintAcceptMethod, error: LintErrorMethod): void;
2916+
visit(node: Node, stop: LintStopMethod, error: LintErrorMethod): void;
29132917
}
29142918

29152919
export interface SyntacticLintProviderStatic {

src/compiler/utilities.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -456,12 +456,16 @@ namespace ts {
456456
export function createExtensionDiagnosticForNode(node: Node, extension: string, message: string): Diagnostic {
457457
const sourceFile = getSourceFileOfNode(node);
458458
const span = getErrorSpanForNode(sourceFile, node);
459+
return createExtensionDiagnostic(extension, message, sourceFile, span.start, span.length);
460+
}
461+
462+
export function createExtensionDiagnostic(extension: string, message: string, file?: SourceFile, start?: number, length?: number): Diagnostic {
459463
return {
460-
file: sourceFile,
464+
file: file,
461465
messageText: message,
462466
code: extension,
463-
start: span.start,
464-
length: span.length,
467+
start: start,
468+
length: length,
465469
category: DiagnosticCategory.Extension
466470
};
467471
}

tests/cases/unittests/extensionAPI.ts

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -165,13 +165,13 @@ import * as tsi from "typescript";
165165
export abstract class SyntacticLintWalker implements tsi.LintWalker {
166166
private static __tsCompilerExtensionKind: tsi.ExtensionKind.SyntacticLint = "syntactic-lint";
167167
constructor(protected ts: typeof tsi, protected args: any) {}
168-
abstract visit(node: tsi.Node, accept: tsi.LintAcceptMethod, error: tsi.LintErrorMethod): void;
168+
abstract visit(node: tsi.Node, stop: tsi.LintStopMethod, error: tsi.LintErrorMethod): void;
169169
}
170170
171171
export abstract class SemanticLintWalker implements tsi.LintWalker {
172172
private static __tsCompilerExtensionKind: tsi.ExtensionKind.SemanticLint = "semantic-lint";
173173
constructor(protected ts: typeof tsi, protected checker: tsi.TypeChecker, protected args: any) {}
174-
abstract visit(node: tsi.Node, accept: tsi.LintAcceptMethod, error: tsi.LintErrorMethod): void;
174+
abstract visit(node: tsi.Node, stop: tsi.LintStopMethod, error: tsi.LintErrorMethod): void;
175175
}
176176
177177
export abstract class LanguageServiceProvider implements tsi.LanguageServiceProvider {
@@ -244,13 +244,12 @@ import {SyntacticLintWalker} from "typescript-plugin-api";
244244
245245
export default class IsNamedFoo extends SyntacticLintWalker {
246246
constructor(ts, args) { super(ts, args); }
247-
visit(node, accept, error) {
247+
visit(node, stop, error) {
248248
if (node.kind === this.ts.SyntaxKind.Identifier) {
249249
if (node.text.toLowerCase() === "foo") {
250250
error("Identifier 'foo' is forbidden.", node);
251251
}
252252
}
253-
accept();
254253
}
255254
}
256255
`,
@@ -268,14 +267,13 @@ import {SemanticLintWalker} from "typescript-plugin-api";
268267
269268
export default class IsValueFoo extends SemanticLintWalker {
270269
constructor(ts, checker, args) { super(ts, checker, args); }
271-
visit(node, accept, error) {
270+
visit(node, stop, error) {
272271
const type = this.checker.getTypeAtLocation(node);
273272
if (type.flags & this.ts.TypeFlags.StringLiteral) {
274273
if (node.text === "foo") {
275274
error("String literal type 'foo' is forbidden.", node);
276275
}
277276
}
278-
accept();
279277
}
280278
}
281279
`,
@@ -293,15 +291,14 @@ import {SyntacticLintWalker} from "typescript-plugin-api";
293291
294292
export default class IsNamedX extends SyntacticLintWalker {
295293
constructor(ts, args) { super(ts, args); }
296-
visit(node, accept, error) {
294+
visit(node, stop, error) {
297295
if (node.kind === this.ts.SyntaxKind.Identifier) {
298296
for (let i = 0; i<this.args.length; i++) {
299297
if (node.text.toLowerCase() === this.args[i]) {
300298
error(\`Identifier \${this.args[i]} is forbidden.\`, node);
301299
}
302300
}
303301
}
304-
accept();
305302
}
306303
}
307304
`
@@ -319,51 +316,47 @@ import {SyntacticLintWalker, SemanticLintWalker} from "typescript-plugin-api";
319316
320317
export class IsNamedFoo extends SyntacticLintWalker {
321318
constructor(ts, args) { super(ts, args); }
322-
visit(node, accept, error) {
319+
visit(node, stop, error) {
323320
if (node.kind === this.ts.SyntaxKind.Identifier) {
324321
if (node.text.toLowerCase() === "foo") {
325322
error("Identifier 'foo' is forbidden.", node);
326323
}
327324
}
328-
accept();
329325
}
330326
}
331327
332328
export class IsNamedBar extends SyntacticLintWalker {
333329
constructor(ts, args) { super(ts, args); }
334-
visit(node, accept, error) {
330+
visit(node, stop, error) {
335331
if (node.kind === this.ts.SyntaxKind.Identifier) {
336332
if (node.text.toLowerCase() === "bar") {
337333
error("Identifier 'bar' is forbidden.", node);
338334
}
339335
}
340-
accept();
341336
}
342337
}
343338
344339
export class IsValueFoo extends SemanticLintWalker {
345340
constructor(ts, checker, args) { super(ts, checker, args); }
346-
visit(node, accept, error) {
341+
visit(node, stop, error) {
347342
const type = this.checker.getTypeAtLocation(node);
348343
if (type.flags & this.ts.TypeFlags.StringLiteral) {
349344
if (node.text === "foo") {
350345
error("String literal type 'foo' is forbidden.", node);
351346
}
352347
}
353-
accept();
354348
}
355349
}
356350
357351
export class IsValueBar extends SemanticLintWalker {
358352
constructor(ts, checker, args) { super(ts, checker, args); }
359-
visit(node, accept, error) {
353+
visit(node, stop, error) {
360354
const type = this.checker.getTypeAtLocation(node);
361355
if (type.flags & this.ts.TypeFlags.StringLiteral) {
362356
if (node.text === "bar") {
363357
error("String literal type 'bar' is forbidden.", node);
364358
}
365359
}
366-
accept();
367360
}
368361
}
369362
`

0 commit comments

Comments
 (0)