Merge branch 'master' into APISamples

Conflicts:
	tests/baselines/reference/APISample_compile.js
	tests/baselines/reference/APISample_compile.types
	tests/baselines/reference/APISample_linter.js
	tests/baselines/reference/APISample_linter.types
	tests/baselines/reference/APISample_linter.types.pull
	tests/baselines/reference/APISample_transform.js
	tests/baselines/reference/APISample_transform.types
	tests/baselines/reference/APISample_watcher.js
	tests/baselines/reference/APISample_watcher.types
This commit is contained in:
Mohamed Hegazy 2015-04-02 16:45:44 -07:00
commit facbe843d1
34 changed files with 7199 additions and 91 deletions

View File

@ -506,6 +506,22 @@ module ts {
Function_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions: { code: 7024, category: DiagnosticCategory.Error, key: "Function implicitly has return type 'any' because it does not have a return type annotation and is referenced directly or indirectly in one of its return expressions." },
You_cannot_rename_this_element: { code: 8000, category: DiagnosticCategory.Error, key: "You cannot rename this element." },
You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library: { code: 8001, category: DiagnosticCategory.Error, key: "You cannot rename elements that are defined in the standard TypeScript library." },
import_can_only_be_used_in_a_ts_file: { code: 8002, category: DiagnosticCategory.Error, key: "'import ... =' can only be used in a .ts file." },
export_can_only_be_used_in_a_ts_file: { code: 8003, category: DiagnosticCategory.Error, key: "'export=' can only be used in a .ts file." },
type_parameter_declarations_can_only_be_used_in_a_ts_file: { code: 8004, category: DiagnosticCategory.Error, key: "'type parameter declarations' can only be used in a .ts file." },
implements_clauses_can_only_be_used_in_a_ts_file: { code: 8005, category: DiagnosticCategory.Error, key: "'implements clauses' can only be used in a .ts file." },
interface_declarations_can_only_be_used_in_a_ts_file: { code: 8006, category: DiagnosticCategory.Error, key: "'interface declarations' can only be used in a .ts file." },
module_declarations_can_only_be_used_in_a_ts_file: { code: 8007, category: DiagnosticCategory.Error, key: "'module declarations' can only be used in a .ts file." },
type_aliases_can_only_be_used_in_a_ts_file: { code: 8008, category: DiagnosticCategory.Error, key: "'type aliases' can only be used in a .ts file." },
_0_can_only_be_used_in_a_ts_file: { code: 8009, category: DiagnosticCategory.Error, key: "'{0}' can only be used in a .ts file." },
types_can_only_be_used_in_a_ts_file: { code: 8010, category: DiagnosticCategory.Error, key: "'types' can only be used in a .ts file." },
type_arguments_can_only_be_used_in_a_ts_file: { code: 8011, category: DiagnosticCategory.Error, key: "'type arguments' can only be used in a .ts file." },
parameter_modifiers_can_only_be_used_in_a_ts_file: { code: 8012, category: DiagnosticCategory.Error, key: "'parameter modifiers' can only be used in a .ts file." },
can_only_be_used_in_a_ts_file: { code: 8013, category: DiagnosticCategory.Error, key: "'?' can only be used in a .ts file." },
property_declarations_can_only_be_used_in_a_ts_file: { code: 8014, category: DiagnosticCategory.Error, key: "'property declarations' can only be used in a .ts file." },
enum_declarations_can_only_be_used_in_a_ts_file: { code: 8015, category: DiagnosticCategory.Error, key: "'enum declarations' can only be used in a .ts file." },
type_assertion_expressions_can_only_be_used_in_a_ts_file: { code: 8016, category: DiagnosticCategory.Error, key: "'type assertion expressions' can only be used in a .ts file." },
decorators_can_only_be_used_in_a_ts_file: { code: 8017, category: DiagnosticCategory.Error, key: "'decorators' can only be used in a .ts file." },
yield_expressions_are_not_currently_supported: { code: 9000, category: DiagnosticCategory.Error, key: "'yield' expressions are not currently supported." },
Generators_are_not_currently_supported: { code: 9001, category: DiagnosticCategory.Error, key: "Generators are not currently supported." },
Only_identifiers_Slashqualified_names_with_optional_type_arguments_are_currently_supported_in_a_class_extends_clauses: { code: 9002, category: DiagnosticCategory.Error, key: "Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clauses." },

View File

@ -2017,6 +2017,71 @@
"category": "Error",
"code": 8001
},
"'import ... =' can only be used in a .ts file.": {
"category": "Error",
"code": 8002
},
"'export=' can only be used in a .ts file.": {
"category": "Error",
"code": 8003
},
"'type parameter declarations' can only be used in a .ts file.": {
"category": "Error",
"code": 8004
},
"'implements clauses' can only be used in a .ts file.": {
"category": "Error",
"code": 8005
},
"'interface declarations' can only be used in a .ts file.": {
"category": "Error",
"code": 8006
},
"'module declarations' can only be used in a .ts file.": {
"category": "Error",
"code": 8007
},
"'type aliases' can only be used in a .ts file.": {
"category": "Error",
"code": 8008
},
"'{0}' can only be used in a .ts file.": {
"category": "Error",
"code": 8009
},
"'types' can only be used in a .ts file.": {
"category": "Error",
"code": 8010
},
"'type arguments' can only be used in a .ts file.": {
"category": "Error",
"code": 8011
},
"'parameter modifiers' can only be used in a .ts file.": {
"category": "Error",
"code": 8012
},
"'?' can only be used in a .ts file.": {
"category": "Error",
"code": 8013
},
"'property declarations' can only be used in a .ts file.": {
"category": "Error",
"code": 8014
},
"'enum declarations' can only be used in a .ts file.": {
"category": "Error",
"code": 8015
},
"'type assertion expressions' can only be used in a .ts file.": {
"category": "Error",
"code": 8016
},
"'decorators' can only be used in a .ts file.": {
"category": "Error",
"code": 8017
},
"'yield' expressions are not currently supported.": {
"category": "Error",
"code": 9000

View File

@ -828,7 +828,7 @@ module ts {
// to reuse are already at the appropriate position in the new text. That way when we
// reuse them, we don't have to figure out if they need to be adjusted. Second, it makes
// it very easy to determine if we can reuse a node. If the node's position is at where
// we are in the text, then we can reuse it. Otherwise we can't. If hte node's position
// we are in the text, then we can reuse it. Otherwise we can't. If the node's position
// is ahead of us, then we'll need to rescan tokens. If the node's position is behind
// us, then we'll need to skip it or crumble it as appropriate
//
@ -1033,7 +1033,7 @@ module ts {
// that some tokens that would be considered identifiers may be considered keywords.
//
// When adding more parser context flags, consider which is the more common case that the
// flag will be in. This should be hte 'false' state for that flag. The reason for this is
// flag will be in. This should be the 'false' state for that flag. The reason for this is
// that we don't store data in our nodes unless the value is in the *non-default* state. So,
// for example, more often than code 'allows-in' (or doesn't 'disallow-in'). We opt for
// 'disallow-in' set to 'false'. Otherwise, if we had 'allowsIn' set to 'true', then almost
@ -1044,7 +1044,7 @@ module ts {
//
// An important thing about these context concepts. By default they are effectively inherited
// while parsing through every grammar production. i.e. if you don't change them, then when
// you parse a sub-production, it will have the same context values as hte parent production.
// you parse a sub-production, it will have the same context values as the parent production.
// This is great most of the time. After all, consider all the 'expression' grammar productions
// and how nearly all of them pass along the 'in' and 'yield' context values:
//
@ -1836,7 +1836,7 @@ module ts {
// some node, then we cannot get a node from the old source tree. This is because we
// want to mark the next node we encounter as being unusable.
//
// Note: This may be too conservative. Perhaps we could reuse hte node and set the bit
// Note: This may be too conservative. Perhaps we could reuse the node and set the bit
// on it (or its leftmost child) as having the error. For now though, being conservative
// is nice and likely won't ever affect perf.
if (parseErrorBeforeNextFinishedNode) {

View File

@ -14,6 +14,7 @@
//
/// <reference path='..\services\services.ts' />
/// <reference path='..\services\shims.ts' />
/// <reference path='harnessLanguageService.ts' />
/// <reference path='harness.ts' />
/// <reference path='fourslashRunner.ts' />
@ -115,7 +116,7 @@ module FourSlash {
// Name of testcase metadata including ts.CompilerOptions properties that will be used by globalOptions
// To add additional option, add property into the testOptMetadataNames, refer the property in either globalMetadataNames or fileMetadataNames
// Add cases into convertGlobalOptionsToCompilationsSettings function for the compiler to acknowledge such option from meta data
var testOptMetadataNames = {
var metadataOptionNames = {
baselineFile: 'BaselineFile',
declaration: 'declaration',
emitThisFile: 'emitThisFile', // This flag is used for testing getEmitOutput feature. It allows test-cases to indicate what file to be output in multiple files project
@ -126,14 +127,15 @@ module FourSlash {
outDir: 'outDir',
sourceMap: 'sourceMap',
sourceRoot: 'sourceRoot',
allowNonTsExtensions: 'allowNonTsExtensions',
resolveReference: 'ResolveReference', // This flag is used to specify entry file for resolve file references. The flag is only allow once per test file
};
// List of allowed metadata names
var fileMetadataNames = [testOptMetadataNames.fileName, testOptMetadataNames.emitThisFile, testOptMetadataNames.resolveReference];
var globalMetadataNames = [testOptMetadataNames.baselineFile, testOptMetadataNames.declaration,
testOptMetadataNames.mapRoot, testOptMetadataNames.module, testOptMetadataNames.out,
testOptMetadataNames.outDir, testOptMetadataNames.sourceMap, testOptMetadataNames.sourceRoot]
var fileMetadataNames = [metadataOptionNames.fileName, metadataOptionNames.emitThisFile, metadataOptionNames.resolveReference];
var globalMetadataNames = [metadataOptionNames.allowNonTsExtensions, metadataOptionNames.baselineFile, metadataOptionNames.declaration,
metadataOptionNames.mapRoot, metadataOptionNames.module, metadataOptionNames.out,
metadataOptionNames.outDir, metadataOptionNames.sourceMap, metadataOptionNames.sourceRoot]
function convertGlobalOptionsToCompilerOptions(globalOptions: { [idx: string]: string }): ts.CompilerOptions {
var settings: ts.CompilerOptions = { target: ts.ScriptTarget.ES5 };
@ -141,13 +143,16 @@ module FourSlash {
for (var prop in globalOptions) {
if (globalOptions.hasOwnProperty(prop)) {
switch (prop) {
case testOptMetadataNames.declaration:
case metadataOptionNames.allowNonTsExtensions:
settings.allowNonTsExtensions = true;
break;
case metadataOptionNames.declaration:
settings.declaration = true;
break;
case testOptMetadataNames.mapRoot:
case metadataOptionNames.mapRoot:
settings.mapRoot = globalOptions[prop];
break;
case testOptMetadataNames.module:
case metadataOptionNames.module:
// create appropriate external module target for CompilationSettings
switch (globalOptions[prop]) {
case "AMD":
@ -162,16 +167,16 @@ module FourSlash {
break;
}
break;
case testOptMetadataNames.out:
case metadataOptionNames.out:
settings.out = globalOptions[prop];
break;
case testOptMetadataNames.outDir:
case metadataOptionNames.outDir:
settings.outDir = globalOptions[prop];
break;
case testOptMetadataNames.sourceMap:
case metadataOptionNames.sourceMap:
settings.sourceMap = true;
break;
case testOptMetadataNames.sourceRoot:
case metadataOptionNames.sourceRoot:
settings.sourceRoot = globalOptions[prop];
break;
}
@ -303,7 +308,7 @@ module FourSlash {
ts.forEach(testData.files, file => {
// Create map between fileName and its content for easily looking up when resolveReference flag is specified
this.inputFiles[file.fileName] = file.content;
if (!startResolveFileRef && file.fileOptions[testOptMetadataNames.resolveReference]) {
if (!startResolveFileRef && file.fileOptions[metadataOptionNames.resolveReference]) {
startResolveFileRef = file;
} else if (startResolveFileRef) {
// If entry point for resolving file references is already specified, report duplication error
@ -793,6 +798,13 @@ module FourSlash {
return "\nActual " + name + ":\n\t" + actualValue + "\nExpected value:\n\t" + expectedValue;
}
public getSemanticDiagnostics(expected: string) {
var diagnostics = this.languageService.getSemanticDiagnostics(this.activeFile.fileName);
var realized = ts.realizeDiagnostics(diagnostics, "\r\n");
var actual = JSON.stringify(realized, null, " ");
assert.equal(actual, expected);
}
public verifyQuickInfoString(negative: boolean, expectedText?: string, expectedDocumentation?: string) {
[expectedText, expectedDocumentation].forEach(str => {
if (str) {
@ -1131,7 +1143,7 @@ module FourSlash {
Harness.Baseline.runBaseline(
"Breakpoint Locations for " + this.activeFile.fileName,
this.testData.globalOptions[testOptMetadataNames.baselineFile],
this.testData.globalOptions[metadataOptionNames.baselineFile],
() => {
return this.baselineCurrentFileLocations(pos => this.getBreakpointStatementLocation(pos));
},
@ -1146,7 +1158,7 @@ module FourSlash {
var allFourSlashFiles = this.testData.files;
for (var idx = 0; idx < allFourSlashFiles.length; ++idx) {
var file = allFourSlashFiles[idx];
if (file.fileOptions[testOptMetadataNames.emitThisFile]) {
if (file.fileOptions[metadataOptionNames.emitThisFile]) {
// Find a file with the flag emitThisFile turned on
emitFiles.push(file);
}
@ -1159,7 +1171,7 @@ module FourSlash {
Harness.Baseline.runBaseline(
"Generate getEmitOutput baseline : " + emitFiles.join(" "),
this.testData.globalOptions[testOptMetadataNames.baselineFile],
this.testData.globalOptions[metadataOptionNames.baselineFile],
() => {
var resultString = "";
// Loop through all the emittedFiles and emit them one by one
@ -1704,7 +1716,7 @@ module FourSlash {
Harness.Baseline.runBaseline(
"Name OrDottedNameSpans for " + this.activeFile.fileName,
this.testData.globalOptions[testOptMetadataNames.baselineFile],
this.testData.globalOptions[metadataOptionNames.baselineFile],
() => {
return this.baselineCurrentFileLocations(pos =>
this.getNameOrDottedNameSpan(pos));
@ -2280,7 +2292,7 @@ module FourSlash {
if (globalMetadataNamesIndex === -1) {
if (fileMetadataNamesIndex === -1) {
throw new Error('Unrecognized metadata name "' + match[1] + '". Available global metadata names are: ' + globalMetadataNames.join(', ') + '; file metadata names are: ' + fileMetadataNames.join(', '));
} else if (fileMetadataNamesIndex === fileMetadataNames.indexOf(testOptMetadataNames.fileName)) {
} else if (fileMetadataNamesIndex === fileMetadataNames.indexOf(metadataOptionNames.fileName)) {
// Found an @FileName directive, if this is not the first then create a new subfile
if (currentFileContent) {
var file = parseFileContent(currentFileContent, currentFileName, markerPositions, markers, ranges);

View File

@ -617,12 +617,29 @@ declare module ts.server.protocol {
* Optional modifiers for the kind (such as 'public').
*/
kindModifiers: string;
/**
* A string that is used for comparing completion items so that they can be ordered. This
* is often the same as the name but may be different in certain circumstances.
*/
sortText: string;
}
/**
* Additional completion entry details, available on demand
*/
export interface CompletionEntryDetails extends CompletionEntry {
export interface CompletionEntryDetails {
/**
* The symbol's name.
*/
name: string;
/**
* The symbol's kind (such as 'className' or 'parameterName').
*/
kind: string;
/**
* Optional modifiers for the kind (such as 'public').
*/
kindModifiers: string;
/**
* Display parts of the symbol (similar to quick info).
*/

View File

@ -22,7 +22,7 @@ module ts.NavigateTo {
continue;
}
// It was a match! If the pattern has dots in it, then also see if hte
// It was a match! If the pattern has dots in it, then also see if the
// declaration container matches as well.
if (patternMatcher.patternContainsDots) {
let containers = getContainers(declaration);

View File

@ -471,7 +471,7 @@ module ts {
// Helper function to compare two matches to determine which is better. Matches are first
// ordered by kind (so all prefix matches always beat all substring matches). Then, if the
// match is a camel case match, the relative weights of hte match are used to determine
// match is a camel case match, the relative weights of the match are used to determine
// which is better (with a greater weight being better). Then if the match is of the same
// type, then a case sensitive match is considered better than an insensitive one.
function patternMatchCompareTo(match1: PatternMatch, match2: PatternMatch): number {

View File

@ -1148,6 +1148,7 @@ module ts {
name: string;
kind: string; // see ScriptElementKind
kindModifiers: string; // see ScriptElementKindModifier, comma separated
sortText: string;
}
export interface CompletionEntryDetails {
@ -1316,6 +1317,7 @@ module ts {
// TODO: move these to enums
export class ScriptElementKind {
static unknown = "";
static warning = "warning";
// predefined type (void) or keyword (class)
static keyword = "keyword";
@ -2166,7 +2168,8 @@ module ts {
keywordCompletions.push({
name: tokenToString(i),
kind: ScriptElementKind.keyword,
kindModifiers: ScriptElementKindModifier.none
kindModifiers: ScriptElementKindModifier.none,
sortText: "0"
});
}
@ -2430,15 +2433,26 @@ module ts {
return program.getSyntacticDiagnostics(getValidSourceFile(fileName));
}
function isJavaScript(fileName: string) {
return fileExtensionIs(fileName, ".js");
}
/**
* getSemanticDiagnostiscs return array of Diagnostics. If '-d' is not enabled, only report semantic errors
* If '-d' enabled, report both semantic and emitter errors
*/
function getSemanticDiagnostics(fileName: string) {
function getSemanticDiagnostics(fileName: string): Diagnostic[] {
synchronizeHostData();
let targetSourceFile = getValidSourceFile(fileName);
// For JavaScript files, we don't want to report the normal typescript semantic errors.
// Instead, we just report errors for using TypeScript-only constructs from within a
// JavaScript file.
if (isJavaScript(fileName)) {
return getJavaScriptSemanticDiagnostics(targetSourceFile);
}
// Only perform the action per file regardless of '-out' flag as LanguageServiceHost is expected to call this function per file.
// Therefore only get diagnostics for given file.
@ -2452,35 +2466,199 @@ module ts {
return concatenate(semanticDiagnostics, declarationDiagnostics);
}
function getJavaScriptSemanticDiagnostics(sourceFile: SourceFile): Diagnostic[] {
let diagnostics: Diagnostic[] = [];
walk(sourceFile);
return diagnostics;
function walk(node: Node): boolean {
if (!node) {
return false;
}
switch (node.kind) {
case SyntaxKind.ImportEqualsDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.import_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.ExportAssignment:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.export_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.ClassDeclaration:
let classDeclaration = <ClassDeclaration>node;
if (checkModifiers(classDeclaration.modifiers) ||
checkTypeParameters(classDeclaration.typeParameters)) {
return true;
}
break;
case SyntaxKind.HeritageClause:
let heritageClause = <HeritageClause>node;
if (heritageClause.token === SyntaxKind.ImplementsKeyword) {
diagnostics.push(createDiagnosticForNode(node, Diagnostics.implements_clauses_can_only_be_used_in_a_ts_file));
return true;
}
break;
case SyntaxKind.InterfaceDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.interface_declarations_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.ModuleDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.module_declarations_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.TypeAliasDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.type_aliases_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.FunctionExpression:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ArrowFunction:
case SyntaxKind.FunctionDeclaration:
let functionDeclaration = <FunctionLikeDeclaration>node;
if (checkModifiers(functionDeclaration.modifiers) ||
checkTypeParameters(functionDeclaration.typeParameters) ||
checkTypeAnnotation(functionDeclaration.type)) {
return true;
}
break;
case SyntaxKind.VariableStatement:
let variableStatement = <VariableStatement>node;
if (checkModifiers(variableStatement.modifiers)) {
return true;
}
break;
case SyntaxKind.VariableDeclaration:
let variableDeclaration = <VariableDeclaration>node;
if (checkTypeAnnotation(variableDeclaration.type)) {
return true;
}
break;
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
let expression = <CallExpression>node;
if (expression.typeArguments && expression.typeArguments.length > 0) {
let start = expression.typeArguments.pos;
diagnostics.push(createFileDiagnostic(sourceFile, start, expression.typeArguments.end - start,
Diagnostics.type_arguments_can_only_be_used_in_a_ts_file));
return true;
}
break;
case SyntaxKind.Parameter:
let parameter = <ParameterDeclaration>node;
if (parameter.modifiers) {
let start = parameter.modifiers.pos;
diagnostics.push(createFileDiagnostic(sourceFile, start, parameter.modifiers.end - start,
Diagnostics.parameter_modifiers_can_only_be_used_in_a_ts_file));
return true;
}
if (parameter.questionToken) {
diagnostics.push(createDiagnosticForNode(parameter.questionToken, Diagnostics.can_only_be_used_in_a_ts_file));
return true;
}
if (parameter.type) {
diagnostics.push(createDiagnosticForNode(parameter.type, Diagnostics.types_can_only_be_used_in_a_ts_file));
return true;
}
break;
case SyntaxKind.PropertyDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.property_declarations_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.EnumDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.enum_declarations_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.TypeAssertionExpression:
let typeAssertionExpression = <TypeAssertion>node;
diagnostics.push(createDiagnosticForNode(typeAssertionExpression.type, Diagnostics.type_assertion_expressions_can_only_be_used_in_a_ts_file));
return true;
case SyntaxKind.Decorator:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.decorators_can_only_be_used_in_a_ts_file));
return true;
}
return forEachChild(node, walk);
}
function checkTypeParameters(typeParameters: NodeArray<TypeParameterDeclaration>): boolean {
if (typeParameters) {
let start = typeParameters.pos;
diagnostics.push(createFileDiagnostic(sourceFile, start, typeParameters.end - start, Diagnostics.type_parameter_declarations_can_only_be_used_in_a_ts_file));
return true;
}
return false;
}
function checkTypeAnnotation(type: TypeNode): boolean {
if (type) {
diagnostics.push(createDiagnosticForNode(type, Diagnostics.types_can_only_be_used_in_a_ts_file));
return true;
}
return false;
}
function checkModifiers(modifiers: ModifiersArray): boolean {
if (modifiers) {
for (let modifier of modifiers) {
switch (modifier.kind) {
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
case SyntaxKind.DeclareKeyword:
diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind)));
return true;
// These are all legal modifiers.
case SyntaxKind.StaticKeyword:
case SyntaxKind.ExportKeyword:
case SyntaxKind.ConstKeyword:
case SyntaxKind.DefaultKeyword:
}
}
}
return false;
}
}
function getCompilerOptionsDiagnostics() {
synchronizeHostData();
return program.getGlobalDiagnostics();
}
/// Completion
function getCompletionEntryDisplayName(symbol: Symbol, target: ScriptTarget, performCharacterChecks: boolean): string {
function getCompletionEntryDisplayNameForSymbol(symbol: Symbol, target: ScriptTarget, performCharacterChecks: boolean): string {
let displayName = symbol.getName();
if (displayName) {
// If this is the default export, get the name of the declaration if it exists
if (displayName === "default") {
let localSymbol = getLocalSymbolForExportDefault(symbol);
if (localSymbol && localSymbol.name) {
displayName = symbol.valueDeclaration.localSymbol.name;
}
}
let firstCharCode = displayName.charCodeAt(0);
// First check of the displayName is not external module; if it is an external module, it is not valid entry
if ((symbol.flags & SymbolFlags.Namespace) && (firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote)) {
// If the symbol is external module, don't show it in the completion list
// (i.e declare module "http" { let x; } | // <= request completion here, "http" should not be there)
return undefined;
}
}
return getCompletionEntryDisplayName(displayName, target, performCharacterChecks);
}
function getCompletionEntryDisplayName(displayName: string, target: ScriptTarget, performCharacterChecks: boolean): string {
if (!displayName) {
return undefined;
}
// If this is the default export, get the name of the declaration if it exists
if (displayName === "default") {
let localSymbol = getLocalSymbolForExportDefault(symbol);
if (localSymbol && localSymbol.name) {
displayName = symbol.valueDeclaration.localSymbol.name;
}
}
let firstCharCode = displayName.charCodeAt(0);
// First check of the displayName is not external module; if it is an external module, it is not valid entry
if ((symbol.flags & SymbolFlags.Namespace) && (firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote)) {
// If the symbol is external module, don't show it in the completion list
// (i.e declare module "http" { let x; } | // <= request completion here, "http" should not be there)
return undefined;
}
if (displayName && displayName.length >= 2 && firstCharCode === displayName.charCodeAt(displayName.length - 1) &&
if (displayName.length >= 2 &&
firstCharCode === displayName.charCodeAt(displayName.length - 1) &&
(firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote)) {
// If the user entered name for the symbol was quoted, removing the quotes is not enough, as the name could be an
// invalid identifier name. We need to check if whatever was inside the quotes is actually a valid identifier name.
@ -2510,19 +2688,24 @@ module ts {
// Try to get a valid display name for this symbol, if we could not find one, then ignore it.
// We would like to only show things that can be added after a dot, so for instance numeric properties can
// not be accessed with a dot (a.1 <- invalid)
let displayName = getCompletionEntryDisplayName(symbol, program.getCompilerOptions().target, /*performCharacterChecks:*/ true);
let displayName = getCompletionEntryDisplayNameForSymbol(symbol, program.getCompilerOptions().target, /*performCharacterChecks:*/ true);
if (!displayName) {
return undefined;
}
// TODO(drosen): Right now we just permit *all* semantic meanings when calling 'getSymbolKind'
// which is permissible given that it is backwards compatible; but really we should consider
// passing the meaning for the node so that we don't report that a suggestion for a value is an interface.
// We COULD also just do what 'getSymbolModifiers' does, which is to use the first declaration.
// TODO(drosen): Right now we just permit *all* semantic meanings when calling
// 'getSymbolKind' which is permissible given that it is backwards compatible; but
// really we should consider passing the meaning for the node so that we don't report
// that a suggestion for a value is an interface. We COULD also just do what
// 'getSymbolModifiers' does, which is to use the first declaration.
// Use a 'sortText' of 0' so that all symbol completion entries come before any other
// entries (like JavaScript identifier entries).
return {
name: displayName,
kind: getSymbolKind(symbol, typeChecker, location),
kindModifiers: getSymbolModifiers(symbol)
kindModifiers: getSymbolModifiers(symbol),
sortText: "0",
};
}
@ -2566,8 +2749,9 @@ module ts {
return undefined;
}
// Find the node where completion is requested on, in the case of a completion after a dot, it is the member access expression
// otherwise, it is a request for all visible symbols in the scope, and the node is the current location
// Find the node where completion is requested on, in the case of a completion after
// a dot, it is the member access expression other wise, it is a request for all
// visible symbols in the scope, and the node is the current location.
let node = currentToken;
let isRightOfDot = false;
if (contextToken && contextToken.kind === SyntaxKind.DotToken && contextToken.parent.kind === SyntaxKind.PropertyAccessExpression) {
@ -2585,11 +2769,26 @@ module ts {
let semanticStart = new Date().getTime();
let isMemberCompletion: boolean;
let isNewIdentifierLocation: boolean;
let symbols: Symbol[];
let symbols: Symbol[] = [];
if (isRightOfDot) {
getTypeScriptMemberSymbols();
}
else {
// For JavaScript or TypeScript, if we're not after a dot, then just try to get the
// global symbols in scope. These results should be valid for either language as
// the set of symbols that can be referenced from this location.
if (!tryGetGlobalSymbols()) {
return undefined;
}
}
log("getCompletionData: Semantic work: " + (new Date().getTime() - semanticStart));
return { symbols, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot };
function getTypeScriptMemberSymbols(): void {
// Right of dot member completion list
symbols = [];
isMemberCompletion = true;
isNewIdentifierLocation = false;
@ -2622,7 +2821,8 @@ module ts {
});
}
}
else {
function tryGetGlobalSymbols(): boolean {
let containingObjectLiteral = getContainingObjectLiteralApplicableForCompletion(contextToken);
if (containingObjectLiteral) {
// Object literal expression, look up possible property names from contextual type
@ -2631,7 +2831,7 @@ module ts {
let contextualType = typeInfoResolver.getContextualType(containingObjectLiteral);
if (!contextualType) {
return undefined;
return false;
}
let contextualTypeMembers = typeInfoResolver.getPropertiesOfType(contextualType);
@ -2704,12 +2904,10 @@ module ts {
let symbolMeanings = SymbolFlags.Type | SymbolFlags.Value | SymbolFlags.Namespace | SymbolFlags.Alias;
symbols = typeInfoResolver.getSymbolsInScope(scopeNode, symbolMeanings);
}
return true;
}
log("getCompletionData: Semantic work: " + (new Date().getTime() - semanticStart));
return { symbols, isMemberCompletion, isNewIdentifierLocation, location };
/**
* Finds the first node that "embraces" the position, so that one may
* accurately aggregate locals from the closest containing scope.
@ -3016,12 +3214,20 @@ module ts {
return undefined;
}
let { symbols, isMemberCompletion, isNewIdentifierLocation, location } = completionData;
if (!symbols || symbols.length === 0) {
return undefined;
}
let { symbols, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot } = completionData;
var entries = getCompletionEntriesFromSymbols(symbols);
let entries: CompletionEntry[];
if (isRightOfDot && isJavaScript(fileName)) {
entries = getCompletionEntriesFromSymbols(symbols);
addRange(entries, getJavaScriptCompletionEntries());
}
else {
if (!symbols || symbols.length === 0) {
return undefined;
}
entries = getCompletionEntriesFromSymbols(symbols);
}
// Add keywords if this is not a member completion list
if (!isMemberCompletion) {
@ -3030,21 +3236,51 @@ module ts {
return { isMemberCompletion, isNewIdentifierLocation, entries };
function getCompletionEntriesFromSymbols(symbols: Symbol[]): CompletionEntry[] {
let start = new Date().getTime();
var entries: CompletionEntry[] = [];
var nameToSymbol: Map<Symbol> = {};
function getJavaScriptCompletionEntries(): CompletionEntry[] {
let entries: CompletionEntry[] = [];
let allNames: Map<string> = {};
let target = program.getCompilerOptions().target;
for (let symbol of symbols) {
let entry = createCompletionEntry(symbol, typeInfoResolver, location);
if (entry) {
let id = escapeIdentifier(entry.name);
if (!lookUp(nameToSymbol, id)) {
entries.push(entry);
nameToSymbol[id] = symbol;
for (let sourceFile of program.getSourceFiles()) {
let nameTable = getNameTable(sourceFile);
for (let name in nameTable) {
if (!allNames[name]) {
allNames[name] = name;
let displayName = getCompletionEntryDisplayName(name, target, /*performCharacterChecks:*/ true);
if (displayName) {
let entry = {
name: displayName,
kind: ScriptElementKind.warning,
kindModifiers: "",
sortText: "1"
};
entries.push(entry);
}
}
}
}
return entries;
}
function getCompletionEntriesFromSymbols(symbols: Symbol[]): CompletionEntry[] {
let start = new Date().getTime();
var entries: CompletionEntry[] = [];
if (symbols) {
var nameToSymbol: Map<Symbol> = {};
for (let symbol of symbols) {
let entry = createCompletionEntry(symbol, typeInfoResolver, location);
if (entry) {
let id = escapeIdentifier(entry.name);
if (!lookUp(nameToSymbol, id)) {
entries.push(entry);
nameToSymbol[id] = symbol;
}
}
}
}
log("getCompletionsAtPosition: getCompletionEntriesFromSymbols: " + (new Date().getTime() - start));
return entries;
}
@ -3063,7 +3299,7 @@ module ts {
// We don't need to perform character checks here because we're only comparing the
// name against 'entryName' (which is known to be good), not building a new
// completion entry.
let symbol = forEach(symbols, s => getCompletionEntryDisplayName(s, target, /*performCharacterChecks:*/ false) === entryName ? s : undefined);
let symbol = forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(s, target, /*performCharacterChecks:*/ false) === entryName ? s : undefined);
if (symbol) {
let displayPartsDocumentationsAndSymbolKind = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, getValidSourceFile(fileName), location, typeInfoResolver, location, SemanticMeaning.All);

View File

@ -331,6 +331,22 @@ module ts {
}
}
/* @internal */
export function realizeDiagnostics(diagnostics: Diagnostic[], newLine: string): { message: string; start: number; length: number; category: string; } []{
return diagnostics.map(d => realizeDiagnostic(d, newLine));
}
function realizeDiagnostic(diagnostic: Diagnostic, newLine: string): { message: string; start: number; length: number; category: string; } {
return {
message: flattenDiagnosticMessageText(diagnostic.messageText, newLine),
start: diagnostic.start,
length: diagnostic.length,
/// TODO: no need for the tolowerCase call
category: DiagnosticCategory[diagnostic.category].toLowerCase(),
code: diagnostic.code
};
}
class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim {
private logger: Logger;
@ -391,18 +407,7 @@ module ts {
private realizeDiagnostics(diagnostics: Diagnostic[]): { message: string; start: number; length: number; category: string; }[]{
var newLine = this.getNewLine();
return diagnostics.map(d => this.realizeDiagnostic(d, newLine));
}
private realizeDiagnostic(diagnostic: Diagnostic, newLine: string): { message: string; start: number; length: number; category: string; } {
return {
message: flattenDiagnosticMessageText(diagnostic.messageText, newLine),
start: diagnostic.start,
length: diagnostic.length,
/// TODO: no need for the tolowerCase call
category: DiagnosticCategory[diagnostic.category].toLowerCase(),
code: diagnostic.code
};
return ts.realizeDiagnostics(diagnostics, newLine);
}
public getSyntacticClassifications(fileName: string, start: number, length: number): string {

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,7 @@
// this line triggers a semantic/syntactic error check, remove line when 788570 is fixed
edit.insert('');
debugger;
goTo.marker('1');
verify.completionListContains("multiM", "module multiM", "this is multi declare module\nthi is multi module 2\nthis is multi module 3 comment");

View File

@ -7,7 +7,7 @@
//// declare module 'https' {
//// }
//// /*2*/
debugger;
goTo.marker("1");
verify.not.completionListContains("http");
goTo.marker("2");

View File

@ -439,6 +439,10 @@ module FourSlashInterface {
displayParts: ts.SymbolDisplayPart[], documentation: ts.SymbolDisplayPart[]) {
FourSlash.currentTestState.verifyQuickInfoDisplayParts(kind, kindModifiers, textSpan, displayParts, documentation);
}
public getSemanticDiagnostics(expected: string) {
FourSlash.currentTestState.getSemanticDiagnostics(expected);
}
}
export class edit {

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// import a = b;
verify.getSemanticDiagnostics(`[
{
"message": "'import ... =' can only be used in a .ts file.",
"start": 0,
"length": 13,
"category": "error",
"code": 8002
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// function F<T>() { }
verify.getSemanticDiagnostics(`[
{
"message": "'type parameter declarations' can only be used in a .ts file.",
"start": 11,
"length": 1,
"category": "error",
"code": 8004
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// function F(): number { }
verify.getSemanticDiagnostics(`[
{
"message": "'types' can only be used in a .ts file.",
"start": 14,
"length": 6,
"category": "error",
"code": 8010
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// declare var v;
verify.getSemanticDiagnostics(`[
{
"message": "'declare' can only be used in a .ts file.",
"start": 0,
"length": 7,
"category": "error",
"code": 8009
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// var v: () => number;
verify.getSemanticDiagnostics(`[
{
"message": "'types' can only be used in a .ts file.",
"start": 7,
"length": 12,
"category": "error",
"code": 8010
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// Foo<number>();
verify.getSemanticDiagnostics(`[
{
"message": "'type arguments' can only be used in a .ts file.",
"start": 4,
"length": 6,
"category": "error",
"code": 8011
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// function F(public p) { }
verify.getSemanticDiagnostics(`[
{
"message": "'parameter modifiers' can only be used in a .ts file.",
"start": 11,
"length": 6,
"category": "error",
"code": 8012
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// function F(p?) { }
verify.getSemanticDiagnostics(`[
{
"message": "'?' can only be used in a .ts file.",
"start": 12,
"length": 1,
"category": "error",
"code": 8013
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// function F(a: number) { }
verify.getSemanticDiagnostics(`[
{
"message": "'types' can only be used in a .ts file.",
"start": 14,
"length": 6,
"category": "error",
"code": 8010
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// class C { v }
verify.getSemanticDiagnostics(`[
{
"message": "'property declarations' can only be used in a .ts file.",
"start": 10,
"length": 1,
"category": "error",
"code": 8014
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// enum E { }
verify.getSemanticDiagnostics(`[
{
"message": "'enum declarations' can only be used in a .ts file.",
"start": 5,
"length": 1,
"category": "error",
"code": 8015
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// export = b;
verify.getSemanticDiagnostics(`[
{
"message": "'export=' can only be used in a .ts file.",
"start": 0,
"length": 11,
"category": "error",
"code": 8003
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// var v = <string>undefined;
verify.getSemanticDiagnostics(`[
{
"message": "'type assertion expressions' can only be used in a .ts file.",
"start": 9,
"length": 6,
"category": "error",
"code": 8016
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// @internal class C {}
verify.getSemanticDiagnostics(`[
{
"message": "'decorators' can only be used in a .ts file.",
"start": 0,
"length": 9,
"category": "error",
"code": 8017
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// class C<T> { }
verify.getSemanticDiagnostics(`[
{
"message": "'type parameter declarations' can only be used in a .ts file.",
"start": 8,
"length": 1,
"category": "error",
"code": 8004
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// public class C { }
verify.getSemanticDiagnostics(`[
{
"message": "'public' can only be used in a .ts file.",
"start": 0,
"length": 6,
"category": "error",
"code": 8009
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// class C implements D { }
verify.getSemanticDiagnostics(`[
{
"message": "'implements clauses' can only be used in a .ts file.",
"start": 8,
"length": 12,
"category": "error",
"code": 8005
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// interface I { }
verify.getSemanticDiagnostics(`[
{
"message": "'interface declarations' can only be used in a .ts file.",
"start": 10,
"length": 1,
"category": "error",
"code": 8006
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// module M { }
verify.getSemanticDiagnostics(`[
{
"message": "'module declarations' can only be used in a .ts file.",
"start": 7,
"length": 1,
"category": "error",
"code": 8007
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// type a = b;
verify.getSemanticDiagnostics(`[
{
"message": "'type aliases' can only be used in a .ts file.",
"start": 0,
"length": 11,
"category": "error",
"code": 8008
}
]`);

View File

@ -0,0 +1,15 @@
/// <reference path="fourslash.ts" />
// @allowNonTsExtensions: true
// @Filename: a.js
//// public function F() { }
verify.getSemanticDiagnostics(`[
{
"message": "'public' can only be used in a .ts file.",
"start": 0,
"length": 6,
"category": "error",
"code": 8009
}
]`);