-
Notifications
You must be signed in to change notification settings - Fork 12.9k
RFC: Extensibility model #9038
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: Extensibility model #9038
Changes from 1 commit
8b3aeb8
8583037
a7ae427
a03e465
4eee39d
bff6b05
f4384f6
b874ad9
d716dc9
1433411
0f9a816
0e9650c
dec0bf8
06dbfb7
80d89fb
67f6e26
2c15bb3
02834c4
257e939
9425485
c2f1cc5
3480c7c
adccddf
af9c1e1
908d9e7
a4762a8
3036843
69f0473
680a75b
19846c3
8283881
4fd46c8
7eca070
ab90cba
8a972d9
dad1bbe
9405dd3
5c97262
9f10c74
625e3cf
ed12a9c
a011aec
b4fc76c
1582d10
b5b7817
84c683e
ee23587
5d2618b
67063cc
50735ae
732da00
eab3c5a
86fcfb4
e173bc6
4676ca2
b8ca16a
563d71f
ae66e99
842d3c3
805bc2f
40b35c4
e5c342a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -176,6 +176,26 @@ namespace ts { | |
return array1.concat(array2); | ||
} | ||
|
||
export function flatten<T>(array1: T[][]): T[] { | ||
if (!array1 || !array1.length) return <any>array1; | ||
return [].concat(...array1); | ||
} | ||
|
||
6D40 | export function groupBy<T>(array: T[], classifier: (item: T) => string): {[index: string]: T[]}; | |
export function groupBy<T>(array: T[], classifier: (item: T) => number): {[index: number]: T[]}; | ||
export function groupBy<T>(array: T[], classifier: (item: T) => (string | number)): {[index: string]: T[], [index: number]: T[]} { | ||
if (!array || !array.length) return undefined; | ||
const ret: {[index: string]: T[], [index: number]: T[]} = {}; | ||
for (let i = 0, len = array.length; i < len; i++) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for-of here? #Resolved |
||
const result = classifier(array[i]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would use the name |
||
if (!ret[result]) { | ||
ret[result] = []; | ||
} | ||
ret[result].push(array[i]); | ||
} | ||
return ret; | ||
} | ||
|
||
export function deduplicate<T>(array: T[], areEqual?: (a: T, b: T) => boolean): T[] { | ||
let result: T[]; | ||
if (array) { | ||
|
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -115,7 +115,12 @@ namespace ts { | |
} | ||
|
||
const category = DiagnosticCategory[diagnostic.category].toLowerCase(); | ||
output += `${ category } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }${ sys.newLine }`; | ||
if (diagnostic.category === DiagnosticCategory.Extension) { | ||
output += `${ category } ${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }${ sys.newLine }`; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we report the name of the extension that reported the error? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is actually what |
||
} | ||
else { | ||
output += `${ category } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }${ sys.newLine }`; | ||
} | ||
|
||
sys.write(output); | ||
} | ||
|
@@ -604,13 +609,16 @@ namespace ts { | |
// First get and report any syntactic errors. | ||
diagnostics = program.getSyntacticDiagnostics(); | ||
|
||
// Count extension diagnostics and ignore them for determining continued error reporting | ||
const extensionDiagnostics = filter(diagnostics, d => d.category === DiagnosticCategory.Extension).length; | ||
|
||
// If we didn't have any syntactic errors, then also try getting the global and | ||
// semantic errors. | ||
if (diagnostics.length === 0) { | ||
diagnostics = program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics()); | ||
if (diagnostics.length === extensionDiagnostics) { | ||
diagnostics = diagnostics.concat(program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics())); | ||
|
||
if (diagnostics.length === 0) { | ||
diagnostics = program.getSemanticDiagnostics(); | ||
if (diagnostics.length === extensionDiagnostics) { | ||
diagnostics = diagnostics.concat(program.getSemanticDiagnostics()); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1736,6 +1736,11 @@ namespace ts { | |
*/ | ||
getTypeChecker(): TypeChecker; | ||
|
||
/** | ||
* Gets a map of loaded compiler extensions | ||
*/ | ||
getCompilerExtensions(): ExtensionCollectionMap; | ||
|
||
/* @internal */ getCommonSourceDirectory(): string; | ||
|
||
// For testing purposes only. Should not be used by any other consumers (including the | ||
|
@@ -1812,6 +1817,7 @@ namespace ts { | |
getSourceFiles(): SourceFile[]; | ||
getSourceFile(fileName: string): SourceFile; | ||
getResolvedTypeReferenceDirectives(): Map<ResolvedTypeReferenceDirective>; | ||
getCompilerExtensions(): ExtensionCollectionMap; | ||
} | ||
|
||
export interface TypeChecker { | ||
|
@@ -2496,13 +2502,14 @@ namespace ts { | |
length: number; | ||
messageText: string | DiagnosticMessageChain; | ||
category: DiagnosticCategory; | ||
code: number; | ||
code: number | string; | ||
} | ||
|
||
export enum DiagnosticCategory { | ||
Warning, | ||
Error, | ||
Message, | ||
Extension, | ||
} | ||
|
||
export enum ModuleResolutionKind { | ||
|
@@ -2586,6 +2593,7 @@ namespace ts { | |
typesSearchPaths?: string[]; | ||
/*@internal*/ version?: boolean; | ||
/*@internal*/ watch?: boolean; | ||
extensions?: string[] | Map<any>; | ||
|
||
[option: string]: CompilerOptionsValue | undefined; | ||
} | ||
|
@@ -2893,6 +2901,57 @@ namespace ts { | |
failedLookupLocations: string[]; | ||
} | ||
|
||
export type LintErrorMethod = (err: string, span: Node) => void; | ||
export type LintAcceptMethod = () => void; | ||
|
||
/* | ||
* Walkers call accept to decend into the node's children | ||
* Walkers call error to add errors to the output. | ||
*/ | ||
export interface LintWalker { | ||
visit(node: Node, accept: LintAcceptMethod, error: LintErrorMethod): void; | ||
} | ||
|
||
export interface SyntacticLintProviderStatic { | ||
new (typescript: typeof ts, args: any): LintWalker; | ||
} | ||
|
||
export interface SemanticLintProviderStatic { | ||
new (typescript: typeof ts, checker: TypeChecker, args: any): LintWalker; | ||
} | ||
|
||
export namespace ExtensionKind { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we really need this pseudo-string-valued-enum? Can we just use the string literals themselves to avoid having to look up this value on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. String literals don't get completions in value positions; namespace members do (and furthermore the namespace helps unify and organize them, much like enums). If you're suggesting we inline them, then maybe we should implement generic constant in-lining. ;) Plus, access to them never happens on a particularly hot code path, so the perf difference should't matter. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Or, maybe we should consider completions for string literals? |
||
export const SemanticLint: "semantic-lint" = "semantic-lint"; | ||
export type SemanticLint = "semantic-lint"; | ||
export const SyntacticLint: "syntactic-lint" = "syntactic-lint"; | ||
export type SyntacticLint = "syntactic-lint"; | ||
} | ||
export type ExtensionKind = ExtensionKind.SemanticLint | ExtensionKind.SyntacticLint; | ||
|
||
export interface ExtensionCollectionMap { | ||
"syntactic-lint"?: SyntacticLintExtension[]; | ||
"semantic-lint"?: SemanticLintExtension[]; | ||
[index: string]: Extension[] | undefined; | ||
} | ||
|
||
export interface ExtensionBase { | ||
name: string; | ||
args: any; | ||
kind: ExtensionKind; | ||
} | ||
|
||
// @kind(ExtensionKind.SyntacticLint) | ||
export interface SyntacticLintExtension extends ExtensionBase { | ||
ctor: SyntacticLintProviderStatic; | ||
} | ||
|
||
// @kind(ExtensionKind.SemanticLint) | ||
export interface SemanticLintExtension extends ExtensionBase { | ||
ctor: SemanticLintProviderStatic; | ||
} | ||
|
||
export type Extension = SyntacticLintExtension | SemanticLintExtension; | ||
|
||
export interface CompilerHost extends ModuleResolutionHost { | ||
getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile; | ||
getSourceFileByPath?(fileName: string, path: Path, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile; | ||
|
@@ -2919,6 +2978,14 @@ namespace ts { | |
* This method is a companion for 'resolveModuleNames' and is used to resolve 'types' references to actual type declaration files | ||
*/ | ||
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[]; | ||
|
||
/** | ||
* Delegates the loading of compiler extensions to the compiler host. | ||
* The function should return the result of executing the code of an extension | ||
* - its exported members. These members will be searched for objects who have been decorated with | ||
* specific flags. | ||
*/ | ||
loadExtension?(extension: string): any; | ||
} | ||
|
||
export interface TextSpan { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the file is a module, we should return the module symbol.