8000 Functional extension loading & lint passes · microsoft/TypeScript@8b3aeb8 · GitHub
[go: up one dir, main page]

Skip to content
Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 8b3aeb8

Browse files
committed
Functional extension loading & lint passes
1 parent 6d99b2f commit 8b3aeb8

File tree

12 files changed

+806
-26
lines changed

12 files changed

+806
-26
lines changed

Jakefile.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,8 @@ var harnessSources = harnessCoreSources.concat([
157157
"convertCompilerOptionsFromJson.ts",
158158
"convertTypingOptionsFromJson.ts",
159159
"tsserverProjectSystem.ts",
160-
"matchFiles.ts"
160+
"matchFiles.ts",
161+
"extensionAPI.ts",
161162
].map(function (f) {
162163
return path.join(unittestsDirectory, f);
163164
})).concat([
@@ -527,7 +528,7 @@ compileFile(servicesFile, servicesSources,[builtLocalDirectory, copyright].conca
527528

528529
// Node package definition file to be distributed without the package. Created by replacing
529530
// 'ts' namespace with '"typescript"' as a module.
530-
var nodeStandaloneDefinitionsFileContents = definitionFileContents.replace(/declare (namespace|module) ts/g, 'declare module "typescript"');
531+
var nodeStandaloneDefinitionsFileContents = definitionFileContents.replace(/declare (namespace|module) ts {/g, 'declare module "typescript" {\n import * as ts from "typescript";');
531532
fs.writeFileSync(nodeStandaloneDefinitionsFile, nodeStandaloneDefinitionsFileContents);
532533
});
533534

src/compiler/checker.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17258,6 +17258,10 @@ namespace ts {
1725817258
return getTypeForVariableLikeDeclaration(<VariableLikeDeclaration>node.parent, /*includeOptionality*/ true);
1725917259
}
1726017260

17261+
if (node.kind === SyntaxKind.SourceFile) {
17262+
return unknownType;
17263+
}
172 A3E2 64+
1726117265
if (isInRightSideOfImportOrExportAssignment(<Identifier>node)) {
1726217266
const symbol = getSymbolAtLocation(node);
1726317267
const declaredType = symbol && getDeclaredTypeOfSymbol(symbol);

src/compiler/commandLineParser.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,12 @@ namespace ts {
268268
experimental: true,
269269
description: Diagnostics.Enables_experimental_support_for_emitting_type_metadata_for_decorators
270270
},
271+
{
272+
name: "extensions",
273+
type: "object",
274+
isTSConfigOnly: true,
275+
description: Diagnostics.List_of_compiler_extensions_to_require
276+
},
271277
{
272278
name: "moduleResolution",
273279
type: {

src/compiler/core.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,26 @@ namespace ts {
176176
return array1.concat(array2);
177177
}
178178

179+
export function flatten<T>(array1: T[][]): T[] {
180+
if (!array1 || !array1.length) return <any>array1;
181+
return [].concat(...array1);
182+
}
183+
184+
export function groupBy<T>(array: T[], classifier: (item: T) => string): {[index: string]: T[]};
185+
export function groupBy<T>(array: T[], classifier: (item: T) => number): {[index: number]: T[]};
186+
export function groupBy<T>(array: T[], classifier: (item: T) => (string | number)): {[index: string]: T[], [index: number]: T[]} {
187+
if (!array || !array.length) return undefined;
188+
const ret: {[index: string]: T[], [index: number]: T[]} = {};
189+
for (let i = 0, len = array.length; i < len; i++) {
190+
const result = classifier(array[i]);
191+
if (!ret[result]) {
192+
ret[result] = [];
193+
}
194+
ret[result].push(array[i]);
195+
}
196+
return ret;
197+
}
198+
179199
export function deduplicate<T>(array: T[], areEqual?: (a: T, b: T) => boolean): T[] {
180200
let result: T[];
181201
if (array) {

src/compiler/diagnosticMessages.json

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2656,7 +2656,7 @@
26562656
"category": "Message",
26572657
"code": 6099
26582658
},
2659-
"'package.json' does not have 'types' field.": {
2659+
"'package.json' does not have '{0}' field.": {
26602660
"category": "Message",
26612661
"code": 6100
26622662
},
@@ -2789,6 +2789,19 @@
27892789
"code": 6132
27902790
},
27912791

2792+
"List of compiler extensions to require.": {
2793+
"category": "Message",
2794+
"code": 6150
2795+
},
2796+
"Extension loading failed with error '{0}'.": {
2797+
"category": "Error",
2798+
"code": 6151
2799+
},
2800+
"Extension '{0}' exported member '{1}' has extension kind '{2}', but was type '{3}' when type '{4}' was expected.": {
2801+
"category": "Error",
2802+
"code": 6152
2803+
},
2804+
27922805
"Variable '{0}' implicitly has an '{1}' type.": {
27932806
"category": "Error",
27942807
"code": 7005

src/compiler/program.ts

Lines changed: 204 additions & 15 deletions
Large diffs are not rendered by default.

src/compiler/sys.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ namespace ts {
3232
getMemoryUsage?(): number;
3333
exit(exitCode?: number): void;
3434
realpath?(path: string): string;
35+
loadExtension?(name: string): any;
3536
}
3637

3738
export interface FileWatcher {
@@ -547,6 +548,9 @@ namespace ts {
547548
},
548549
realpath(path: string): string {
549550
return _fs.realpathSync(path);
551+
},
552+
loadExtension(name) {
553+
return require(name);
550554
}
551555
};
552556
}

src/compiler/tsc.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,12 @@ namespace ts {
115115
}
116116

117117
const category = DiagnosticCategory[diagnostic.category].toLowerCase();
118-
output += `${ category } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }${ sys.newLine }`;
118+
if (diagnostic.category === DiagnosticCategory.Extension) {
119+
output += `${ category } ${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }${ sys.newLine }`;
120+
}
121+
else {
122+
output += `${ category } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }${ sys.newLine }`;
123+
}
119124

120125
sys.write(output);
121126
}
@@ -604,13 +609,16 @@ namespace ts {
604609
// First get and report any syntactic errors.
605610
diagnostics = program.getSyntacticDiagnostics();
606611

612+
// Count extension diagnostics and ignore them for determining continued error reporting
613+
const extensionDiagnostics = filter(diagnostics, d => d.category === DiagnosticCategory.Extension).length;
614+
607615
// If we didn't have any syntactic errors, then also try getting the global and
608616
// semantic errors.
609-
if (diagnostics.length === 0) {
610-
diagnostics = program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics());
617+
if (diagnostics.length === extensionDiagnostics) {
618+
diagnostics = diagnostics.concat(program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics()));
611619

612-
if (diagnostics.length === 0) {
613-
diagnostics = program.getSemanticDiagnostics();
620+
if (diagnostics.length === extensionDiagnostics) {
621+
diagnostics = diagnostics.concat(program.getSemanticDiagnostics());
614622
}
615623
}
616624

src/compiler/types.ts

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1736,6 +1736,11 @@ namespace ts {
17361736
*/
17371737
getTypeChecker(): TypeChecker;
17381738

1739+
/**
1740+
* Gets a map of loaded compiler extensions
1741+
*/
1742+
getCompilerExtensions(): ExtensionCollectionMap;
1743+
17391744
/* @internal */ getCommonSourceDirectory(): string;
17401745

17411746
// For testing purposes only. Should not be used by any other consumers (including the
@@ -1812,6 +1817,7 @@ namespace ts {
18121817
getSourceFiles(): SourceFile[];
18131818
getSourceFile(fileName: string): SourceFile;
18141819
getResolvedTypeReferenceDirectives(): Map<ResolvedTypeReferenceDirective>;
1820+
getCompilerExtensions(): ExtensionCollectionMap;
18151821
}
18161822

18171823
export interface TypeChecker {
@@ -2496,13 +2502,14 @@ namespace ts {
24962502
length: number;
24972503
messageText: string | DiagnosticMessageChain;
24982504
category: DiagnosticCategory;
2499-
code: number;
2505+
code: number | string;
25002506
}
25012507

25022508
export enum DiagnosticCategory {
25032509
Warning,
25042510
Error,
25052511
Message,
2512+
Extension,
25062513
}
25072514

25082515
export enum ModuleResolutionKind {
@@ -2586,6 +2593,7 @@ namespace ts {
25862593
typesSearchPaths?: string[];
25872594
/*@internal*/ version?: boolean;
25882595
/*@internal*/ watch?: boolean;
2596+
extensions?: string[] | Map<any>;
25892597

25902598
[option: string]: CompilerOptionsValue | undefined;
25912599
}
@@ -2893,6 +2901,57 @@ namespace ts {
28932901
failedLookupLocations: string[];
28942902
}
28952903

2904+
export type LintErrorMethod = (err: string, span: Node) => void;
2905+
export type LintAcceptMethod = () => void;
2906+
2907+
/*
2908+
* Walkers call accept to decend into the node's children
2909+
* Walkers call error to add errors to the output.
2910+
*/
2911+
export interface LintWalker {
2912+
visit(node: Node, accept: LintAcceptMethod, error: LintErrorMethod): void;
2913+
}
2914+
2915+
export interface SyntacticLintProviderStatic {
2916+
new (typescript: typeof ts, args: any): LintWalker;
2917+
}
2918+
2919+
export interface SemanticLintProviderStatic {
2920+
new (typescript: typeof ts, checker: TypeChecker, args: any): LintWalker;
2921+
}
2922+
2923+
export namespace ExtensionKind {
2924+
export const SemanticLint: "semantic-lint" = "semantic-lint";
2925+
export type SemanticLint = "semantic-lint";
2926+
export const SyntacticLint: "syntactic-lint" = "syntactic-lint";
2927+
export type SyntacticLint = "syntactic-lint";
2928+
}
2929+
export type ExtensionKind = ExtensionKind.SemanticLint | ExtensionKind.SyntacticLint;
2930+
2931+
export interface ExtensionCollectionMap {
2932+
"syntactic-lint"?: SyntacticLintExtension[];
2933+
"semantic-lint"?: SemanticLintExtension[];
2934+
[index: string]: Extension[] | undefined;
2935+
}
2936+
2937+
export interface ExtensionBase {
2938+
name: string;
2939+
args: any;
2940+
kind: ExtensionKind;
2941+
}
2942+
2943+
// @kind(ExtensionKind.SyntacticLint)
2944+
export interface SyntacticLintExtension extends ExtensionBase {
2945+
ctor: SyntacticLintProviderStatic;
2946+
}
2947+
2948+
// @kind(ExtensionKind.SemanticLint)
2949+
export interface SemanticLintExtension extends ExtensionBase {
2950+
ctor: SemanticLintProviderStatic;
2951+
}
2952+
2953+
export type Extension = SyntacticLintExtension | SemanticLintExtension;
2954+
28962955
export interface CompilerHost extends ModuleResolutionHost {
28972956
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
28982957
getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile;
@@ -2919,6 +2978,14 @@ namespace ts {
29192978
* This method is a companion for 'resolveModuleNames' and is used to resolve 'types' references to actual type declaration files
29202979
*/
29212980
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
2981+
2982+
/**
2983+
* Delegates the loading of compiler extensions to the compiler host.
2984+
* The function should return the result of executing the code of an extension
2985+
* - its exported members. These members will be searched for objects who have been decorated with
2986+
* specific flags.
2987+
*/
2988+
loadExtension?(extension: string): any;
29222989
}
29232990

29242991
export interface TextSpan {

src/compiler/utilities.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,19 @@ namespace ts {
453453
10000 return createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2);
454454
}
455455

456+
export function createExtensionDiagnosticForNode(node: Node, extension: string, message: string): Diagnostic {
457+
const sourceFile = getSourceFileOfNode(node);
458+
const span = getErrorSpanForNode(sourceFile, node);
459+
return {
460+
file: sourceFile,
461+
messageText: message,
462+
code: extension,
463+
start: span.start,
464+
length: span.length,
465+
category: DiagnosticCategory.Extension
466+
};
467+
}
468+
456469
export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain): Diagnostic {
457470
const sourceFile = getSourceFileOfNode(node);
458471
const span = getErrorSpanForNode(sourceFile, node);

src/services/shims.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,11 +541,11 @@ namespace ts {
541541
}
542542
}
543543

544-
export function realizeDiagnostics(diagnostics: Diagnostic[], newLine: string): { message: string; start: number; length: number; category: string; code: number; }[] {
544+
export function realizeDiagnostics(diagnostics: Diagnostic[], newLine: string): { message: string; start: number; length: number; category: string; code: number | string; }[] {
545545
return diagnostics.map(d => realizeDiagnostic(d, newLine));
546546
}
547547

548-
function realizeDiagnostic(diagnostic: Diagnostic, newLine: string): { message: string; start: number; length: number; category: string; code: number; } {
548+
function realizeDiagnostic(diagnostic: Diagnostic, newLine: string): { message: string; start: number; length: number; category: string; code: number | string; } {
549549
return {
550550
message: flattenDiagnosticMessageText(diagnostic.messageText, newLine),
551551
start: diagnostic.start,

0 commit comments

Comments
 (0)
0