Merge branch 'master' into fallthrough

This commit is contained in:
Andy Hanson
2017-04-12 10:58:03 -07:00
5117 changed files with 35527 additions and 34784 deletions
@@ -0,0 +1,70 @@
/* @internal */
namespace ts.codefix {
registerCodeFix({
errorCodes: getApplicableDiagnosticCodes(),
getCodeActions: getDisableJsDiagnosticsCodeActions
});
function getApplicableDiagnosticCodes(): number[] {
const allDiagnostcs = <MapLike<DiagnosticMessage>>Diagnostics;
return Object.keys(allDiagnostcs)
.filter(d => allDiagnostcs[d] && allDiagnostcs[d].category === DiagnosticCategory.Error)
.map(d => allDiagnostcs[d].code);
}
function getIgnoreCommentLocationForLocation(sourceFile: SourceFile, position: number, newLineCharacter: string) {
const { line } = getLineAndCharacterOfPosition(sourceFile, position);
const lineStartPosition = getStartPositionOfLine(line, sourceFile);
const startPosition = getFirstNonSpaceCharacterPosition(sourceFile.text, lineStartPosition);
// First try to see if we can put the '// @ts-ignore' on the previous line.
// We need to make sure that we are not in the middle of a string literal or a comment.
// We also want to check if the previous line holds a comment for a node on the next line
// if so, we do not want to separate the node from its comment if we can.
if (!isInComment(sourceFile, startPosition) && !isInString(sourceFile, startPosition) && !isInTemplateString(sourceFile, startPosition)) {
const token = getTouchingToken(sourceFile, startPosition);
const tokenLeadingCommnets = getLeadingCommentRangesOfNode(token, sourceFile);
if (!tokenLeadingCommnets || !tokenLeadingCommnets.length || tokenLeadingCommnets[0].pos >= startPosition) {
return {
span: { start: startPosition, length: 0 },
newText: `// @ts-ignore${newLineCharacter}`
};
}
}
// If all fails, add an extra new line immediatlly before the error span.
return {
span: { start: position, length: 0 },
newText: `${position === startPosition ? "" : newLineCharacter}// @ts-ignore${newLineCharacter}`
};
}
function getDisableJsDiagnosticsCodeActions(context: CodeFixContext): CodeAction[] | undefined {
const { sourceFile, program, newLineCharacter, span } = context;
if (!isInJavaScriptFile(sourceFile) || !isCheckJsEnabledForFile(sourceFile, program.getCompilerOptions())) {
return undefined;
}
return [{
description: getLocaleSpecificMessage(Diagnostics.Ignore_this_error_message),
changes: [{
fileName: sourceFile.fileName,
textChanges: [getIgnoreCommentLocationForLocation(sourceFile, span.start, newLineCharacter)]
}]
},
{
description: getLocaleSpecificMessage(Diagnostics.Disable_checking_for_this_file),
changes: [{
fileName: sourceFile.fileName,
textChanges: [{
span: {
start: sourceFile.checkJsDirective ? sourceFile.checkJsDirective.pos : 0,
length: sourceFile.checkJsDirective ? sourceFile.checkJsDirective.end - sourceFile.checkJsDirective.pos : 0
},
newText: `// @ts-nocheck${newLineCharacter}`
}]
}]
}];
}
}
+98 -45
View File
@@ -18,68 +18,121 @@ namespace ts.codefix {
return undefined;
}
const classDeclaration = getContainingClass(token);
if (!classDeclaration) {
if (!isPropertyAccessExpression(token.parent) || token.parent.expression.kind !== SyntaxKind.ThisKeyword) {
return undefined;
}
if (!(token.parent && token.parent.kind === SyntaxKind.PropertyAccessExpression)) {
const classMemberDeclaration = getThisContainer(token, /*includeArrowFunctions*/ false);
if (!isClassElement(classMemberDeclaration)) {
return undefined;
}
if ((token.parent as PropertyAccessExpression).expression.kind !== SyntaxKind.ThisKeyword) {
const classDeclaration = <ClassLikeDeclaration>classMemberDeclaration.parent;
if (!classDeclaration || !isClassLike(classDeclaration)) {
return undefined;
}
let typeNode: TypeNode;
const isStatic = hasModifier(classMemberDeclaration, ModifierFlags.Static);
if (token.parent.parent.kind === SyntaxKind.BinaryExpression) {
const binaryExpression = token.parent.parent as BinaryExpression;
return isInJavaScriptFile(sourceFile) ? getActionsForAddMissingMemberInJavaScriptFile() : getActionsForAddMissingMemberInTypeScriptFile();
const checker = context.program.getTypeChecker();
const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right)));
typeNode = checker.typeToTypeNode(widenedType, classDeclaration) || typeNode;
function getActionsForAddMissingMemberInJavaScriptFile(): CodeAction[] | undefined {
const memberName = token.getText();
if (isStatic) {
if (classDeclaration.kind === SyntaxKind.ClassExpression) {
return undefined;
}
const className = classDeclaration.name.getText();
return [{
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Initialize_static_property_0), [memberName]),
changes: [{
fileName: sourceFile.fileName,
textChanges: [{
span: { start: classDeclaration.getEnd(), length: 0 },
newText: `${context.newLineCharacter}${className}.${memberName} = undefined;${context.newLineCharacter}`
}]
}]
}];
}
else {
const classConstructor = getFirstConstructorWithBody(classDeclaration);
if (!classConstructor) {
return undefined;
}
return [{
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Initialize_property_0_in_the_constructor), [memberName]),
changes: [{
fileName: sourceFile.fileName,
textChanges: [{
span: { start: classConstructor.body.getEnd() - 1, length: 0 },
newText: `this.${memberName} = undefined;${context.newLineCharacter}`
}]
}]
}];
}
}
typeNode = typeNode ? typeNode : createKeywordTypeNode(SyntaxKind.AnyKeyword);
function getActionsForAddMissingMemberInTypeScriptFile(): CodeAction[] | undefined {
let typeNode: TypeNode;
const openBrace = getOpenBraceOfClassLike(classDeclaration, sourceFile);
if (token.parent.parent.kind === SyntaxKind.BinaryExpression) {
const binaryExpression = token.parent.parent as BinaryExpression;
const property = createProperty(
/*decorators*/undefined,
/*modifiers*/ undefined,
token.getText(sourceFile),
/*questionToken*/ undefined,
typeNode,
/*initializer*/ undefined);
const propertyChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
propertyChangeTracker.insertNodeAfter(sourceFile, openBrace, property, { suffix: context.newLineCharacter });
const checker = context.program.getTypeChecker();
const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right)));
typeNode = checker.typeToTypeNode(widenedType, classDeclaration);
}
const stringTypeNode = createKeywordTypeNode(SyntaxKind.StringKeyword);
const indexingParameter = createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
"x",
/*questionToken*/ undefined,
stringTypeNode,
/*initializer*/ undefined);
const indexSignature = createIndexSignatureDeclaration(
/*decorators*/undefined,
/*modifiers*/ undefined,
[indexingParameter],
typeNode);
typeNode = typeNode || createKeywordTypeNode(SyntaxKind.AnyKeyword);
const indexSignatureChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
indexSignatureChangeTracker.insertNodeAfter(sourceFile, openBrace, indexSignature, { suffix: context.newLineCharacter });
const openBrace = getOpenBraceOfClassLike(classDeclaration, sourceFile);
return [{
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_property_0), [token.getText()]),
changes: propertyChangeTracker.getChanges()
},
{
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_missing_property_0), [token.getText()]),
changes: indexSignatureChangeTracker.getChanges()
}];
const property = createProperty(
/*decorators*/undefined,
/*modifiers*/ isStatic ? [createToken(SyntaxKind.StaticKeyword)] : undefined,
token.getText(sourceFile),
/*questionToken*/ undefined,
typeNode,
/*initializer*/ undefined);
const propertyChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
propertyChangeTracker.insertNodeAfter(sourceFile, openBrace, property, { suffix: context.newLineCharacter });
const actions = [{
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_property_0), [token.getText()]),
changes: propertyChangeTracker.getChanges()
}];
if (!isStatic) {
const stringTypeNode = createKeywordTypeNode(SyntaxKind.StringKeyword);
const indexingParameter = createParameter(
/*decorators*/ undefined,
/*modifiers*/ undefined,
/*dotDotDotToken*/ undefined,
"x",
/*questionToken*/ undefined,
stringTypeNode,
/*initializer*/ undefined);
const indexSignature = createIndexSignatureDeclaration(
/*decorators*/ undefined,
/*modifiers*/ undefined,
[indexingParameter],
typeNode);
const indexSignatureChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
indexSignatureChangeTracker.insertNodeAfter(sourceFile, openBrace, indexSignature, { suffix: context.newLineCharacter });
actions.push({
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_missing_property_0), [token.getText()]),
changes: indexSignatureChangeTracker.getChanges()
});
}
return actions;
}
}
}
+1
View File
@@ -7,4 +7,5 @@
/// <reference path="fixForgottenThisPropertyAccess.ts" />
/// <reference path='unusedIdentifierFixes.ts' />
/// <reference path='importFixes.ts' />
/// <reference path='disableJsDiagnostics.ts' />
/// <reference path='helpers.ts' />
+4 -4
View File
@@ -146,7 +146,7 @@ namespace ts.codefix {
/** This is *a* signature with the maximal number of arguments,
* such that if there is a "maximal" signature without rest arguments,
* this is one of them.
*/
*/
let maxArgsSignature = signatures[0];
let minArgumentCount = signatures[0].minArgumentCount;
let someSigHasRestParameter = false;
@@ -194,7 +194,7 @@ namespace ts.codefix {
modifiers,
name,
optional,
/*typeParameters*/undefined,
/*typeParameters*/ undefined,
parameters,
/*returnType*/ undefined);
}
@@ -217,9 +217,9 @@ namespace ts.codefix {
[createThrow(
createNew(
createIdentifier("Error"),
/*typeArguments*/undefined,
/*typeArguments*/ undefined,
[createLiteral("Method not implemented.")]))],
/*multiline*/true);
/*multiline*/ true);
}
function createVisibilityModifier(flags: ModifierFlags) {
+2 -2
View File
@@ -543,12 +543,12 @@ namespace ts.codefix {
}
function getRelativePathIfInDirectory(path: string, directoryPath: string) {
const relativePath = getRelativePathToDirectoryOrUrl(directoryPath, path, directoryPath, getCanonicalFileName, false);
const relativePath = getRelativePathToDirectoryOrUrl(directoryPath, path, directoryPath, getCanonicalFileName, /*isAbsolutePathAnUrl*/ false);
return isRootedDiskPath(relativePath) || startsWith(relativePath, "..") ? undefined : relativePath;
}
function getRelativePath(path: string, directoryPath: string) {
const relativePath = getRelativePathToDirectoryOrUrl(directoryPath, path, directoryPath, getCanonicalFileName, false);
const relativePath = getRelativePathToDirectoryOrUrl(directoryPath, path, directoryPath, getCanonicalFileName, /*isAbsolutePathAnUrl*/ false);
return moduleHasNonRelativeName(relativePath) ? "./" + relativePath : relativePath;
}
}
@@ -118,7 +118,7 @@ namespace ts.codefix {
const nextToken = getTokenAtPosition(sourceFile, importClause.name.end);
if (nextToken && nextToken.kind === SyntaxKind.CommaToken) {
// shift first non-whitespace position after comma to the start position of the node
return deleteRange({ pos: start, end: skipTrivia(sourceFile.text, nextToken.end, /*stopAfterLineBreaks*/ false, /*stopAtComments*/true) });
return deleteRange({ pos: start, end: skipTrivia(sourceFile.text, nextToken.end, /*stopAfterLineBreaks*/ false, /*stopAtComments*/ true) });
}
else {
return deleteNode(importClause.name);
+8 -6
View File
@@ -173,7 +173,7 @@ namespace ts.Completions {
// a['/*completion position*/']
return getStringLiteralCompletionEntriesFromElementAccess(node.parent, typeChecker, compilerOptions.target, log);
}
else if (node.parent.kind === SyntaxKind.ImportDeclaration || isExpressionOfExternalModuleImportEqualsDeclaration(node) || isRequireCall(node.parent, false)) {
else if (node.parent.kind === SyntaxKind.ImportDeclaration || isExpressionOfExternalModuleImportEqualsDeclaration(node) || isRequireCall(node.parent, /*checkArgumentIsStringLiteral*/ false)) {
// Get all known external module names or complete a path to a module
// i.e. import * as ns from "/*completion position*/";
// import x = require("/*completion position*/");
@@ -211,7 +211,7 @@ namespace ts.Completions {
const type = typeChecker.getContextualType((<ObjectLiteralExpression>element.parent));
const entries: CompletionEntry[] = [];
if (type) {
getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, element, /*performCharacterChecks*/false, typeChecker, target, log);
getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, element, /*performCharacterChecks*/ false, typeChecker, target, log);
if (entries.length) {
return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: true, entries };
}
@@ -239,7 +239,7 @@ namespace ts.Completions {
const type = typeChecker.getTypeAtLocation(node.expression);
const entries: CompletionEntry[] = [];
if (type) {
getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, node, /*performCharacterChecks*/false, typeChecker, target, log);
getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, node, /*performCharacterChecks*/ false, typeChecker, target, log);
if (entries.length) {
return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: true, entries };
}
@@ -293,13 +293,14 @@ namespace ts.Completions {
const symbol = forEach(symbols, s => getCompletionEntryDisplayNameForSymbol(typeChecker, s, compilerOptions.target, /*performCharacterChecks*/ false, location) === entryName ? s : undefined);
if (symbol) {
const { displayParts, documentation, symbolKind } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, location, location, SemanticMeaning.All);
const { displayParts, documentation, symbolKind, tags } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, location, location, SemanticMeaning.All);
return {
name: entryName,
kindModifiers: SymbolDisplay.getSymbolModifiers(symbol),
kind: symbolKind,
displayParts,
documentation
documentation,
tags
};
}
}
@@ -312,7 +313,8 @@ namespace ts.Completions {
kind: ScriptElementKind.keyword,
kindModifiers: ScriptElementKindModifier.none,
displayParts: [displayPart(entryName, SymbolDisplayPartKind.keyword)],
documentation: undefined
documentation: undefined,
tags: undefined
};
}
+47 -47
View File
@@ -1,34 +1,34 @@
namespace ts {
/**
* The document registry represents a store of SourceFile objects that can be shared between
* multiple LanguageService instances. A LanguageService instance holds on the SourceFile (AST)
* of files in the context.
* SourceFile objects account for most of the memory usage by the language service. Sharing
* the same DocumentRegistry instance between different instances of LanguageService allow
* for more efficient memory utilization since all projects will share at least the library
* file (lib.d.ts).
*
* A more advanced use of the document registry is to serialize sourceFile objects to disk
* and re-hydrate them when needed.
*
* To create a default DocumentRegistry, use createDocumentRegistry to create one, and pass it
* to all subsequent createLanguageService calls.
*/
* The document registry represents a store of SourceFile objects that can be shared between
* multiple LanguageService instances. A LanguageService instance holds on the SourceFile (AST)
* of files in the context.
* SourceFile objects account for most of the memory usage by the language service. Sharing
* the same DocumentRegistry instance between different instances of LanguageService allow
* for more efficient memory utilization since all projects will share at least the library
* file (lib.d.ts).
*
* A more advanced use of the document registry is to serialize sourceFile objects to disk
* and re-hydrate them when needed.
*
* To create a default DocumentRegistry, use createDocumentRegistry to create one, and pass it
* to all subsequent createLanguageService calls.
*/
export interface DocumentRegistry {
/**
* Request a stored SourceFile with a given fileName and compilationSettings.
* The first call to acquire will call createLanguageServiceSourceFile to generate
* the SourceFile if was not found in the registry.
*
* @param fileName The name of the file requested
* @param compilationSettings Some compilation settings like target affects the
* shape of a the resulting SourceFile. This allows the DocumentRegistry to store
* multiple copies of the same file for different compilation settings.
* @parm scriptSnapshot Text of the file. Only used if the file was not found
* in the registry and a new one was created.
* @parm version Current version of the file. Only used if the file was not found
* in the registry and a new one was created.
*/
* Request a stored SourceFile with a given fileName and compilationSettings.
* The first call to acquire will call createLanguageServiceSourceFile to generate
* the SourceFile if was not found in the registry.
*
* @param fileName The name of the file requested
* @param compilationSettings Some compilation settings like target affects the
* shape of a the resulting SourceFile. This allows the DocumentRegistry to store
* multiple copies of the same file for different compilation settings.
* @parm scriptSnapshot Text of the file. Only used if the file was not found
* in the registry and a new one was created.
* @parm version Current version of the file. Only used if the file was not found
* in the registry and a new one was created.
*/
acquireDocument(
fileName: string,
compilationSettings: CompilerOptions,
@@ -46,17 +46,17 @@ namespace ts {
scriptKind?: ScriptKind): SourceFile;
/**
* Request an updated version of an already existing SourceFile with a given fileName
* and compilationSettings. The update will in-turn call updateLanguageServiceSourceFile
* to get an updated SourceFile.
*
* @param fileName The name of the file requested
* @param compilationSettings Some compilation settings like target affects the
* shape of a the resulting SourceFile. This allows the DocumentRegistry to store
* multiple copies of the same file for different compilation settings.
* @param scriptSnapshot Text of the file.
* @param version Current version of the file.
*/
* Request an updated version of an already existing SourceFile with a given fileName
* and compilationSettings. The update will in-turn call updateLanguageServiceSourceFile
* to get an updated SourceFile.
*
* @param fileName The name of the file requested
* @param compilationSettings Some compilation settings like target affects the
* shape of a the resulting SourceFile. This allows the DocumentRegistry to store
* multiple copies of the same file for different compilation settings.
* @param scriptSnapshot Text of the file.
* @param version Current version of the file.
*/
updateDocument(
fileName: string,
compilationSettings: CompilerOptions,
@@ -75,14 +75,14 @@ namespace ts {
getKeyForCompilationSettings(settings: CompilerOptions): DocumentRegistryBucketKey;
/**
* Informs the DocumentRegistry that a file is not needed any longer.
*
* Note: It is not allowed to call release on a SourceFile that was not acquired from
* this registry originally.
*
* @param fileName The name of the file to be released
* @param compilationSettings The compilation settings used to acquire the file
*/
* Informs the DocumentRegistry that a file is not needed any longer.
*
* Note: It is not allowed to call release on a SourceFile that was not acquired from
* this registry originally.
*
* @param fileName The name of the file to be released
* @param compilationSettings The compilation settings used to acquire the file
*/
releaseDocument(fileName: string, compilationSettings: CompilerOptions): void;
releaseDocumentWithKey(path: Path, key: DocumentRegistryBucketKey): void;
@@ -214,7 +214,7 @@ namespace ts {
}
function releaseDocumentWithKey(path: Path, key: DocumentRegistryBucketKey): void {
const bucket = getBucketForCompilationSettings(key, /*createIfMissing*/false);
const bucket = getBucketForCompilationSettings(key, /*createIfMissing*/ false);
Debug.assert(bucket !== undefined);
const entry = bucket.get(path);
+5 -5
View File
@@ -187,7 +187,7 @@ namespace ts.FindAllReferences {
return { symbol };
}
if (ts.isUntypedOrShorthandAmbientModuleSymbol(aliasedSymbol)) {
if (ts.isShorthandAmbientModuleSymbol(aliasedSymbol)) {
return { symbol, shorthandModuleSymbol: aliasedSymbol };
}
@@ -496,9 +496,9 @@ namespace ts.FindAllReferences {
}
/** Search within node "container" for references for a search value, where the search value is defined as a
* tuple of(searchSymbol, searchText, searchLocation, and searchMeaning).
* searchLocation: a node where the search value
*/
* tuple of(searchSymbol, searchText, searchLocation, and searchMeaning).
* searchLocation: a node where the search value
*/
function getReferencesInNode<T extends DocumentSpan>(container: Node,
searchSymbol: Symbol,
searchText: string,
@@ -701,7 +701,7 @@ namespace ts.FindAllReferences {
}
});
}
};
}
return result;
}
+36 -36
View File
@@ -34,31 +34,31 @@ namespace ts.formatting {
getIndentationForToken(tokenLine: number, tokenKind: SyntaxKind, container: Node): number;
getIndentationForComment(owningToken: SyntaxKind, tokenIndentation: number, container: Node): number;
/**
* Indentation for open and close tokens of the node if it is block or another node that needs special indentation
* ... {
* .........<child>
* ....}
* ____ - indentation
* ____ - delta
**/
* Indentation for open and close tokens of the node if it is block or another node that needs special indentation
* ... {
* .........<child>
* ....}
* ____ - indentation
* ____ - delta
*/
getIndentation(): number;
/**
* Prefered relative indentation for child nodes.
* Delta is used to carry the indentation info
* foo(bar({
* $
* }))
* Both 'foo', 'bar' introduce new indentation with delta = 4, but total indentation in $ is not 8.
* foo: { indentation: 0, delta: 4 }
* bar: { indentation: foo.indentation + foo.delta = 4, delta: 4} however 'foo' and 'bar' are on the same line
* so bar inherits indentation from foo and bar.delta will be 4
*
*/
* Prefered relative indentation for child nodes.
* Delta is used to carry the indentation info
* foo(bar({
* $
* }))
* Both 'foo', 'bar' introduce new indentation with delta = 4, but total indentation in $ is not 8.
* foo: { indentation: 0, delta: 4 }
* bar: { indentation: foo.indentation + foo.delta = 4, delta: 4} however 'foo' and 'bar' are on the same line
* so bar inherits indentation from foo and bar.delta will be 4
*
*/
getDelta(child: TextRangeWithKind): number;
/**
* Formatter calls this function when rule adds or deletes new lines from the text
* so indentation scope can adjust values of indentation and delta.
*/
* Formatter calls this function when rule adds or deletes new lines from the text
* so indentation scope can adjust values of indentation and delta.
*/
recomputeIndentation(lineAddedByFormatting: boolean): void;
}
@@ -205,9 +205,9 @@ namespace ts.formatting {
}
/** formatting is not applied to ranges that contain parse errors.
* This function will return a predicate that for a given text range will tell
* if there are any parse errors that overlap with the range.
*/
* This function will return a predicate that for a given text range will tell
* if there are any parse errors that overlap with the range.
*/
function prepareRangeContainsErrorFunction(errors: Diagnostic[], originalRange: TextRange): (r: TextRange) => boolean {
if (!errors.length) {
return rangeHasNoErrors;
@@ -254,10 +254,10 @@ namespace ts.formatting {
}
/**
* Start of the original range might fall inside the comment - scanner will not yield appropriate results
* This function will look for token that is located before the start of target range
* and return its end as start position for the scanner.
*/
* Start of the original range might fall inside the comment - scanner will not yield appropriate results
* This function will look for token that is located before the start of target range
* and return its end as start position for the scanner.
*/
function getScanStartPosition(enclosingNode: Node, originalRange: TextRange, sourceFile: SourceFile): number {
const start = enclosingNode.getStart(sourceFile);
if (start === originalRange.pos && enclosingNode.end === originalRange.end) {
@@ -388,7 +388,7 @@ namespace ts.formatting {
if (!formattingScanner.isOnToken()) {
const leadingTrivia = formattingScanner.getCurrentLeadingTrivia();
if (leadingTrivia) {
processTrivia(leadingTrivia, enclosingNode, enclosingNode, undefined);
processTrivia(leadingTrivia, enclosingNode, enclosingNode, /*dynamicIndentation*/ undefined);
trimTrailingWhitespacesForRemainingRange();
}
}
@@ -400,12 +400,12 @@ namespace ts.formatting {
// local functions
/** Tries to compute the indentation for a list element.
* If list element is not in range then
* function will pick its actual indentation
* so it can be pushed downstream as inherited indentation.
* If list element is in the range - its indentation will be equal
* to inherited indentation from its predecessors.
*/
* If list element is not in range then
* function will pick its actual indentation
* so it can be pushed downstream as inherited indentation.
* If list element is in the range - its indentation will be equal
* to inherited indentation from its predecessors.
*/
function tryComputeIndentationForListItem(startPos: number,
endPos: number,
parentStartLine: number,
@@ -567,7 +567,7 @@ namespace ts.formatting {
function getEffectiveDelta(delta: number, child: TextRangeWithKind) {
// Delta value should be zero when the node explicitly prevents indentation of the child node
return SmartIndenter.nodeWillIndentChild(node, child, true) ? delta : 0;
return SmartIndenter.nodeWillIndentChild(node, child, /*indentByDefault*/ true) ? delta : 0;
}
}
+2 -2
View File
@@ -297,8 +297,8 @@ namespace ts.formatting {
// Insert a space after { and before } in single-line contexts, but remove space from empty object literals {}.
this.SpaceAfterOpenBrace = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsBraceWrappedContext), RuleAction.Space));
this.SpaceBeforeCloseBrace = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsBraceWrappedContext), RuleAction.Space));
this.NoSpaceAfterOpenBrace = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsBraceWrappedContext), RuleAction.Delete));
this.NoSpaceBeforeCloseBrace = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsBraceWrappedContext), RuleAction.Delete));
this.NoSpaceAfterOpenBrace = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
this.NoSpaceBeforeCloseBrace = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
this.NoSpaceBetweenEmptyBraceBrackets = new Rule(RuleDescriptor.create1(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsObjectContext), RuleAction.Delete));
// Insert new line after { and before } in multi-line contexts.
+1 -1
View File
@@ -18,7 +18,7 @@ namespace ts.GoToImplementation {
else {
// Perform "Find all References" and retrieve only those that are implementations
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(context,
node, sourceFiles, /*findInStrings*/false, /*findInComments*/false, /*isForRename*/false, /*implementations*/true);
node, sourceFiles, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/ false, /*implementations*/ true);
const result = flatMap(referencedSymbols, symbol => symbol.references);
return result && result.length > 0 ? result : undefined;
+22
View File
@@ -70,6 +70,28 @@ namespace ts.JsDoc {
return documentationComment;
}
export function getJsDocTagsFromDeclarations(declarations: Declaration[]) {
// Only collect doc comments from duplicate declarations once.
const tags: JSDocTagInfo[] = [];
forEachUnique(declarations, declaration => {
const jsDocs = getJSDocs(declaration);
if (!jsDocs) {
return;
}
for (const doc of jsDocs) {
const tagsForDoc = (doc as JSDoc).tags;
if (tagsForDoc) {
tags.push(...tagsForDoc.filter(tag => tag.kind === SyntaxKind.JSDocTag).map(jsDocTag => {
return {
name: jsDocTag.tagName.text,
text: jsDocTag.comment
}; }));
}
}
});
return tags;
}
/**
* Iterates through 'array' by index and performs the callback on each element of array until the callback
* returns a truthy value, then returns that value.
+16 -10
View File
@@ -13,7 +13,7 @@ namespace ts.JsTyping {
fileExists: (fileName: string) => boolean;
readFile: (path: string, encoding?: string) => string;
readDirectory: (rootDir: string, extensions: string[], excludes: string[], includes: string[], depth?: number) => string[];
};
}
interface PackageJson {
_requiredBy?: string[];
@@ -23,7 +23,7 @@ namespace ts.JsTyping {
optionalDependencies?: MapLike<string>;
peerDependencies?: MapLike<string>;
typings?: string;
};
}
// A map of loose file names to library names
// that we are confident require typings
@@ -99,8 +99,11 @@ namespace ts.JsTyping {
const bowerJsonPath = combinePaths(searchDir, "bower.json");
getTypingNamesFromJson(bowerJsonPath, filesToWatch);
const bowerComponentsPath = combinePaths(searchDir, "bower_components");
getTypingNamesFromPackagesFolder(bowerComponentsPath);
const nodeModulesPath = combinePaths(searchDir, "node_modules");
getTypingNamesFromNodeModuleFolder(nodeModulesPath);
getTypingNamesFromPackagesFolder(nodeModulesPath);
}
getTypingNamesFromSourceFileNames(fileNames);
@@ -199,20 +202,23 @@ namespace ts.JsTyping {
}
/**
* Infer typing names from node_module folder
* @param nodeModulesPath is the path to the "node_modules" folder
* Infer typing names from packages folder (ex: node_module, bower_components)
* @param packagesFolderPath is the path to the packages folder
*/
function getTypingNamesFromNodeModuleFolder(nodeModulesPath: string) {
function getTypingNamesFromPackagesFolder(packagesFolderPath: string) {
filesToWatch.push(packagesFolderPath);
// Todo: add support for ModuleResolutionHost too
if (!host.directoryExists(nodeModulesPath)) {
if (!host.directoryExists(packagesFolderPath)) {
return;
}
const typingNames: string[] = [];
const fileNames = host.readDirectory(nodeModulesPath, [".json"], /*excludes*/ undefined, /*includes*/ undefined, /*depth*/ 2);
const fileNames = host.readDirectory(packagesFolderPath, [".json"], /*excludes*/ undefined, /*includes*/ undefined, /*depth*/ 2);
for (const fileName of fileNames) {
const normalizedFileName = normalizePath(fileName);
if (getBaseFileName(normalizedFileName) !== "package.json") {
const baseFileName = getBaseFileName(normalizedFileName);
if (baseFileName !== "package.json" && baseFileName !== "bower.json") {
continue;
}
const result = readConfigFile(normalizedFileName, (path: string) => host.readFile(path));
@@ -224,7 +230,7 @@ namespace ts.JsTyping {
// npm 3's package.json contains a "_requiredBy" field
// we should include all the top level module names for npm 2, and only module names whose
// "_requiredBy" field starts with "#" or equals "/" for npm 3.
if (packageJson._requiredBy &&
if (baseFileName === "package.json" && packageJson._requiredBy &&
filter(packageJson._requiredBy, (r: string) => r[0] === "#" || r === "/").length === 0) {
continue;
}
+55 -35
View File
@@ -2,6 +2,36 @@
/* @internal */
namespace ts.NavigationBar {
/**
* Matches all whitespace characters in a string. Eg:
*
* "app.
*
* onactivated"
*
* matches because of the newline, whereas
*
* "app.onactivated"
*
* does not match.
*/
const whiteSpaceRegex = /\s+/g;
// Keep sourceFile handy so we don't have to search for it every time we need to call `getText`.
let curCancellationToken: CancellationToken;
let curSourceFile: SourceFile;
/**
* For performance, we keep navigation bar parents on a stack rather than passing them through each recursion.
* `parent` is the current parent and is *not* stored in parentsStack.
* `startNode` sets a new parent and `endNode` returns to the previous parent.
*/
let parentsStack: NavigationBarNode[] = [];
let parent: NavigationBarNode;
// NavigationBarItem requires an array, but will not mutate it, so just give it this for performance.
let emptyChildItemArray: NavigationBarItem[] = [];
/**
* Represents a navigation bar item and its children.
* The returned NavigationBarItem is more complicated and doesn't include 'parent', so we use these to do work before converting.
@@ -14,22 +44,36 @@ namespace ts.NavigationBar {
indent: number; // # of parents
}
export function getNavigationBarItems(sourceFile: SourceFile): NavigationBarItem[] {
export function getNavigationBarItems(sourceFile: SourceFile, cancellationToken: CancellationToken): NavigationBarItem[] {
curCancellationToken = cancellationToken;
curSourceFile = sourceFile;
const result = map(topLevelItems(rootNavigationBarNode(sourceFile)), convertToTopLevelItem);
curSourceFile = undefined;
return result;
try {
return map(topLevelItems(rootNavigationBarNode(sourceFile)), convertToTopLevelItem);
}
finally {
reset();
}
}
export function getNavigationTree(sourceFile: SourceFile): NavigationTree {
export function getNavigationTree(sourceFile: SourceFile, cancellationToken: CancellationToken): NavigationTree {
curCancellationToken = cancellationToken;
curSourceFile = sourceFile;
const result = convertToTree(rootNavigationBarNode(sourceFile));
try {
return convertToTree(rootNavigationBarNode(sourceFile));
}
finally {
reset();
}
}
function reset() {
curSourceFile = undefined;
return result;
curCancellationToken = undefined;
parentsStack = [];
parent = undefined;
emptyChildItemArray = [];
}
// Keep sourceFile handy so we don't have to search for it every time we need to call `getText`.
let curSourceFile: SourceFile;
function nodeText(node: Node): string {
return node.getText(curSourceFile);
}
@@ -47,14 +91,6 @@ namespace ts.NavigationBar {
}
}
/*
For performance, we keep navigation bar parents on a stack rather than passing them through each recursion.
`parent` is the current parent and is *not* stored in parentsStack.
`startNode` sets a new parent and `endNode` returns to the previous parent.
*/
const parentsStack: NavigationBarNode[] = [];
let parent: NavigationBarNode;
function rootNavigationBarNode(sourceFile: SourceFile): NavigationBarNode {
Debug.assert(!parentsStack.length);
const root: NavigationBarNode = { node: sourceFile, additionalNodes: undefined, parent: undefined, children: undefined, indent: 0 };
@@ -111,6 +147,8 @@ namespace ts.NavigationBar {
/** Look for navigation bar items in node's subtree, adding them to the current `parent`. */
function addChildrenRecursively(node: Node): void {
curCancellationToken.throwIfCancellationRequested();
if (!node || isToken(node)) {
return;
}
@@ -487,9 +525,6 @@ namespace ts.NavigationBar {
}
}
// NavigationBarItem requires an array, but will not mutate it, so just give it this for performance.
const emptyChildItemArray: NavigationBarItem[] = [];
function convertToTree(n: NavigationBarNode): NavigationTree {
return {
text: getItemName(n.node),
@@ -610,19 +645,4 @@ namespace ts.NavigationBar {
function isFunctionOrClassExpression(node: Node): boolean {
return node.kind === SyntaxKind.FunctionExpression || node.kind === SyntaxKind.ArrowFunction || node.kind === SyntaxKind.ClassExpression;
}
/**
* Matches all whitespace characters in a string. Eg:
*
* "app.
*
* onactivated"
*
* matches because of the newline, whereas
*
* "app.onactivated"
*
* does not match.
*/
const whiteSpaceRegex = /\s+/g;
}
+3 -1
View File
@@ -1,6 +1,6 @@
/* @internal */
namespace ts.OutliningElementsCollector {
export function collectElements(sourceFile: SourceFile): OutliningSpan[] {
export function collectElements(sourceFile: SourceFile, cancellationToken: CancellationToken): OutliningSpan[] {
const elements: OutliningSpan[] = [];
const collapseText = "...";
@@ -38,6 +38,7 @@ namespace ts.OutliningElementsCollector {
let singleLineCommentCount = 0;
for (const currentComment of comments) {
cancellationToken.throwIfCancellationRequested();
// For single line comments, combine consecutive ones (2 or more) into
// a single span from the start of the first till the end of the last
@@ -84,6 +85,7 @@ namespace ts.OutliningElementsCollector {
let depth = 0;
const maxDepth = 20;
function walk(n: Node): void {
cancellationToken.throwIfCancellationRequested();
if (depth > maxDepth) {
return;
}
+7 -7
View File
@@ -12,11 +12,11 @@ namespace ts.Completions.PathCompletions {
const extensions = getSupportedExtensions(compilerOptions);
if (compilerOptions.rootDirs) {
entries = getCompletionEntriesForDirectoryFragmentWithRootDirs(
compilerOptions.rootDirs, literalValue, scriptDirectory, extensions, /*includeExtensions*/false, span, compilerOptions, host, scriptPath);
compilerOptions.rootDirs, literalValue, scriptDirectory, extensions, /*includeExtensions*/ false, span, compilerOptions, host, scriptPath);
}
else {
entries = getCompletionEntriesForDirectoryFragment(
literalValue, scriptDirectory, extensions, /*includeExtensions*/false, span, host, scriptPath);
literalValue, scriptDirectory, extensions, /*includeExtensions*/ false, span, host, scriptPath);
}
}
else {
@@ -94,7 +94,7 @@ namespace ts.Completions.PathCompletions {
if (tryDirectoryExists(host, baseDirectory)) {
// Enumerate the available files if possible
const files = tryReadDirectory(host, baseDirectory, extensions, /*exclude*/undefined, /*include*/["./*"]);
const files = tryReadDirectory(host, baseDirectory, extensions, /*exclude*/ undefined, /*include*/ ["./*"]);
if (files) {
/**
@@ -153,7 +153,7 @@ namespace ts.Completions.PathCompletions {
const fileExtensions = getSupportedExtensions(compilerOptions);
const projectDir = compilerOptions.project || host.getCurrentDirectory();
const absolute = isRootedDiskPath(baseUrl) ? baseUrl : combinePaths(projectDir, baseUrl);
result = getCompletionEntriesForDirectoryFragment(fragment, normalizePath(absolute), fileExtensions, /*includeExtensions*/false, span, host);
result = getCompletionEntriesForDirectoryFragment(fragment, normalizePath(absolute), fileExtensions, /*includeExtensions*/ false, span, host);
if (paths) {
for (const path in paths) {
@@ -214,7 +214,7 @@ namespace ts.Completions.PathCompletions {
// doesn't support. For now, this is safer but slower
const includeGlob = normalizedSuffix ? "**/*" : "./*";
const matches = tryReadDirectory(host, baseDirectory, fileExtensions, undefined, [includeGlob]);
const matches = tryReadDirectory(host, baseDirectory, fileExtensions, /*exclude*/ undefined, [includeGlob]);
if (matches) {
const result: string[] = [];
@@ -267,7 +267,7 @@ namespace ts.Completions.PathCompletions {
nonRelativeModules.push(visibleModule.moduleName);
}
else if (startsWith(visibleModule.moduleName, moduleNameFragment)) {
const nestedFiles = tryReadDirectory(host, visibleModule.moduleDir, supportedTypeScriptExtensions, /*exclude*/undefined, /*include*/["./*"]);
const nestedFiles = tryReadDirectory(host, visibleModule.moduleDir, supportedTypeScriptExtensions, /*exclude*/ undefined, /*include*/ ["./*"]);
if (nestedFiles) {
for (let f of nestedFiles) {
f = normalizePath(f);
@@ -327,7 +327,7 @@ namespace ts.Completions.PathCompletions {
if (kind === "path") {
// Give completions for a relative path
const span: TextSpan = getDirectoryFragmentTextSpan(toComplete, range.pos + prefix.length);
completionInfo.entries = getCompletionEntriesForDirectoryFragment(toComplete, scriptPath, getSupportedExtensions(compilerOptions), /*includeExtensions*/true, span, host, sourceFile.path);
completionInfo.entries = getCompletionEntriesForDirectoryFragment(toComplete, scriptPath, getSupportedExtensions(compilerOptions), /*includeExtensions*/ true, span, host, sourceFile.path);
}
else {
// Give completions based on the typings available
+69 -12
View File
@@ -302,6 +302,10 @@ namespace ts {
// symbol has no doc comment, then the empty string will be returned.
documentationComment: SymbolDisplayPart[];
// Undefined is used to indicate the value has not been computed. If, after computing, the
// symbol has no JSDoc tags, then the empty array will be returned.
tags: JSDocTagInfo[];
constructor(flags: SymbolFlags, name: string) {
this.flags = flags;
this.name = name;
@@ -326,6 +330,14 @@ namespace ts {
return this.documentationComment;
}
getJsDocTags(): JSDocTagInfo[] {
if (this.tags === undefined) {
this.tags = JsDoc.getJsDocTagsFromDeclarations(this.declarations);
}
return this.tags;
}
}
class TokenObject<TKind extends SyntaxKind> extends TokenOrIdentifierObject implements Token<TKind> {
@@ -415,6 +427,10 @@ namespace ts {
// symbol has no doc comment, then the empty string will be returned.
documentationComment: SymbolDisplayPart[];
// Undefined is used to indicate the value has not been computed. If, after computing, the
// symbol has no doc comment, then the empty array will be returned.
jsDocTags: JSDocTagInfo[];
constructor(checker: TypeChecker) {
this.checker = checker;
}
@@ -438,6 +454,14 @@ namespace ts {
return this.documentationComment;
}
getJsDocTags(): JSDocTagInfo[] {
if (this.jsDocTags === undefined) {
this.jsDocTags = this.declaration ? JsDoc.getJsDocTagsFromDeclarations([this.declaration]) : [];
}
return this.jsDocTags;
}
}
class SourceFileObject extends NodeObject implements SourceFile {
@@ -482,6 +506,7 @@ namespace ts {
public moduleAugmentations: LiteralExpression[];
private namedDeclarations: Map<Declaration[]>;
public ambientModuleNames: string[];
public checkJsDirective: CheckJsDirective | undefined;
constructor(kind: SyntaxKind, pos: number, end: number) {
super(kind, pos, end);
@@ -982,6 +1007,36 @@ namespace ts {
}
}
/* @internal */
/** A cancellation that throttles calls to the host */
export class ThrottledCancellationToken implements CancellationToken {
// Store when we last tried to cancel. Checking cancellation can be expensive (as we have
// to marshall over to the host layer). So we only bother actually checking once enough
// time has passed.
private lastCancellationCheckTime = 0;
constructor(private hostCancellationToken: HostCancellationToken, private readonly throttleWaitMilliseconds = 20) {
}
public isCancellationRequested(): boolean {
const time = timestamp();
const duration = Math.abs(time - this.lastCancellationCheckTime);
if (duration >= this.throttleWaitMilliseconds) {
// Check no more than once every throttle wait milliseconds
this.lastCancellationCheckTime = time;
return this.hostCancellationToken.isCancellationRequested();
}
return false;
}
public throwIfCancellationRequested(): void {
if (this.isCancellationRequested()) {
throw new OperationCanceledException();
}
}
}
export function createLanguageService(host: LanguageServiceHost,
documentRegistry: DocumentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory())): LanguageService {
@@ -1330,7 +1385,8 @@ namespace ts {
kindModifiers: ScriptElementKindModifier.none,
textSpan: createTextSpan(node.getStart(), node.getWidth()),
displayParts: typeToDisplayParts(typeChecker, type, getContainerNode(node)),
documentation: type.symbol ? type.symbol.getDocumentationComment() : undefined
documentation: type.symbol ? type.symbol.getDocumentationComment() : undefined,
tags: type.symbol ? type.symbol.getJsDocTags() : undefined
};
}
}
@@ -1344,7 +1400,8 @@ namespace ts {
kindModifiers: SymbolDisplay.getSymbolModifiers(symbol),
textSpan: createTextSpan(node.getStart(), node.getWidth()),
displayParts: displayPartsDocumentationsAndKind.displayParts,
documentation: displayPartsDocumentationsAndKind.documentation
documentation: displayPartsDocumentationsAndKind.documentation,
tags: displayPartsDocumentationsAndKind.tags
};
}
@@ -1416,17 +1473,17 @@ namespace ts {
}
function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[] {
const referencedSymbols = findReferencedSymbols(fileName, position, findInStrings, findInComments, /*isForRename*/true);
const referencedSymbols = findReferencedSymbols(fileName, position, findInStrings, findInComments, /*isForRename*/ true);
return FindAllReferences.convertReferences(referencedSymbols);
}
function getReferencesAtPosition(fileName: string, position: number): ReferenceEntry[] {
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/false);
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/ false);
return FindAllReferences.convertReferences(referencedSymbols);
}
function findReferences(fileName: string, position: number): ReferencedSymbol[] {
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/false);
const referencedSymbols = findReferencedSymbols(fileName, position, /*findInStrings*/ false, /*findInComments*/ false, /*isForRename*/ false);
// Only include referenced symbols that have a valid definition.
return filter(referencedSymbols, rs => !!rs.definition);
}
@@ -1553,11 +1610,11 @@ namespace ts {
}
function getNavigationBarItems(fileName: string): NavigationBarItem[] {
return NavigationBar.getNavigationBarItems(syntaxTreeCache.getCurrentSourceFile(fileName));
return NavigationBar.getNavigationBarItems(syntaxTreeCache.getCurrentSourceFile(fileName), cancellationToken);
}
function getNavigationTree(fileName: string): NavigationTree {
return NavigationBar.getNavigationTree(syntaxTreeCache.getCurrentSourceFile(fileName));
return NavigationBar.getNavigationTree(syntaxTreeCache.getCurrentSourceFile(fileName), cancellationToken);
}
function isTsOrTsxFile(fileName: string): boolean {
@@ -1596,7 +1653,7 @@ namespace ts {
function getOutliningSpans(fileName: string): OutliningSpan[] {
// doesn't use compiler - no need to synchronize with host
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
return OutliningElementsCollector.collectElements(sourceFile);
return OutliningElementsCollector.collectElements(sourceFile, cancellationToken);
}
function getBraceMatchingAtPosition(fileName: string, position: number) {
@@ -2075,10 +2132,10 @@ namespace ts {
declare const __dirname: string;
/**
* Get the path of the default library files (lib.d.ts) as distributed with the typescript
* node package.
* The functionality is not supported if the ts module is consumed outside of a node module.
*/
* Get the path of the default library files (lib.d.ts) as distributed with the typescript
* node package.
* The functionality is not supported if the ts module is consumed outside of a node module.
*/
export function getDefaultLibFilePath(options: CompilerOptions): string {
// Check __dirname is defined and that we are on a node.js system.
if (typeof __dirname !== "undefined") {
+2 -25
View File
@@ -49,7 +49,7 @@ namespace ts {
error(s: string): void;
}
/** Public interface of the host of a language service shim instance.*/
/** Public interface of the host of a language service shim instance. */
export interface LanguageServiceShimHost extends Logger {
getCompilationSettings(): string;
@@ -469,29 +469,6 @@ namespace ts {
}
}
/** A cancellation that throttles calls to the host */
class ThrottledCancellationToken implements HostCancellationToken {
// Store when we last tried to cancel. Checking cancellation can be expensive (as we have
// to marshall over to the host layer). So we only bother actually checking once enough
// time has passed.
private lastCancellationCheckTime = 0;
constructor(private hostCancellationToken: HostCancellationToken) {
}
public isCancellationRequested(): boolean {
const time = timestamp();
const duration = Math.abs(time - this.lastCancellationCheckTime);
if (duration > 10) {
// Check no more than once every 10 ms.
this.lastCancellationCheckTime = time;
return this.hostCancellationToken.isCancellationRequested();
}
return false;
}
}
export class CoreServicesShimHostAdapter implements ParseConfigHost, ModuleResolutionHost {
public directoryExists: (directoryName: string) => boolean;
@@ -1249,7 +1226,7 @@ namespace ts {
// Here we expose the TypeScript services as an external module
// so that it may be consumed easily like a node module.
declare var module: any;
declare const module: any;
if (typeof module !== "undefined" && module.exports) {
module.exports = ts;
}
+2 -1
View File
@@ -606,7 +606,8 @@ namespace ts.SignatureHelp {
suffixDisplayParts,
separatorDisplayParts: [punctuationPart(SyntaxKind.CommaToken), spacePart()],
parameters: signatureHelpParameters,
documentation: candidateSignature.getDocumentationComment()
documentation: candidateSignature.getDocumentationComment(),
tags: candidateSignature.getJsDocTags()
};
});
+5 -1
View File
@@ -93,6 +93,7 @@ namespace ts.SymbolDisplay {
const displayParts: SymbolDisplayPart[] = [];
let documentation: SymbolDisplayPart[];
let tags: JSDocTagInfo[];
const symbolFlags = symbol.flags;
let symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(typeChecker, symbol, location);
let hasAddedSymbolInfo: boolean;
@@ -418,6 +419,7 @@ namespace ts.SymbolDisplay {
if (!documentation) {
documentation = symbol.getDocumentationComment();
tags = symbol.getJsDocTags();
if (documentation.length === 0 && symbol.flags & SymbolFlags.Property) {
// For some special property access expressions like `exports.foo = foo` or `module.exports.foo = foo`
// there documentation comments might be attached to the right hand side symbol of their declarations.
@@ -434,6 +436,7 @@ namespace ts.SymbolDisplay {
}
documentation = rhsSymbol.getDocumentationComment();
tags = rhsSymbol.getJsDocTags();
if (documentation.length > 0) {
break;
}
@@ -442,7 +445,7 @@ namespace ts.SymbolDisplay {
}
}
return { displayParts, documentation, symbolKind };
return { displayParts, documentation, symbolKind, tags };
function addNewLineIfDisplayPartsExist() {
if (displayParts.length) {
@@ -500,6 +503,7 @@ namespace ts.SymbolDisplay {
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
}
documentation = signature.getDocumentationComment();
tags = signature.getJsDocTags();
}
function writeTypeParametersOfSymbol(symbol: Symbol, enclosingDeclaration: Node) {
+1 -1
View File
@@ -421,7 +421,7 @@ namespace ts.textChanges {
let changesInFile = changesPerFile.get(c.sourceFile.path);
if (!changesInFile) {
changesPerFile.set(c.sourceFile.path, changesInFile = []);
};
}
changesInFile.push(c);
}
// convert changes
+2 -1
View File
@@ -91,6 +91,7 @@
"codefixes/fixes.ts",
"codefixes/helpers.ts",
"codefixes/importFixes.ts",
"codefixes/unusedIdentifierFixes.ts"
"codefixes/unusedIdentifierFixes.ts",
"codefixes/disableJsDiagnostics.ts"
]
}
+18 -8
View File
@@ -27,6 +27,7 @@ namespace ts {
getName(): string;
getDeclarations(): Declaration[];
getDocumentationComment(): SymbolDisplayPart[];
getJsDocTags(): JSDocTagInfo[];
}
export interface Type {
@@ -49,6 +50,7 @@ namespace ts {
getParameters(): Symbol[];
getReturnType(): Type;
getDocumentationComment(): SymbolDisplayPart[];
getJsDocTags(): JSDocTagInfo[];
}
export interface SourceFile {
@@ -519,12 +521,18 @@ namespace ts {
kind: string; // A ScriptElementKind
}
export interface JSDocTagInfo {
name: string;
text?: string;
}
export interface QuickInfo {
kind: string;
kindModifiers: string;
textSpan: TextSpan;
displayParts: SymbolDisplayPart[];
documentation: SymbolDisplayPart[];
tags: JSDocTagInfo[];
}
export interface RenameInfo {
@@ -558,6 +566,7 @@ namespace ts {
separatorDisplayParts: SymbolDisplayPart[];
parameters: SignatureHelpParameter[];
documentation: SymbolDisplayPart[];
tags: JSDocTagInfo[];
}
/**
@@ -588,10 +597,10 @@ namespace ts {
kindModifiers: string; // see ScriptElementKindModifier, comma separated
sortText: string;
/**
* An optional span that indicates the text to be replaced by this completion item. It will be
* set if the required span differs from the one generated by the default replacement behavior and should
* be used in that case
*/
* An optional span that indicates the text to be replaced by this completion item. It will be
* set if the required span differs from the one generated by the default replacement behavior and should
* be used in that case
*/
replacementSpan?: TextSpan;
}
@@ -601,6 +610,7 @@ namespace ts {
kindModifiers: string; // see ScriptElementKindModifier, comma separated
displayParts: SymbolDisplayPart[];
documentation: SymbolDisplayPart[];
tags: JSDocTagInfo[];
}
export interface OutliningSpan {
@@ -614,9 +624,9 @@ namespace ts {
bannerText: string;
/**
* Whether or not this region should be automatically collapsed when
* the 'Collapse to Definitions' command is invoked.
*/
* Whether or not this region should be automatically collapsed when
* the 'Collapse to Definitions' command is invoked.
*/
autoCollapse: boolean;
}
@@ -788,7 +798,7 @@ namespace ts {
/**
* <JsxTagName attribute1 attribute2={0} />
**/
*/
export const jsxAttribute = "JSX attribute";
}
+15 -8
View File
@@ -705,13 +705,13 @@ namespace ts {
}
/**
* The token on the left of the position is the token that strictly includes the position
* or sits to the left of the cursor if it is on a boundary. For example
*
* fo|o -> will return foo
* foo <comment> |bar -> will return foo
*
*/
* The token on the left of the position is the token that strictly includes the position
* or sits to the left of the cursor if it is on a boundary. For example
*
* fo|o -> will return foo
* foo <comment> |bar -> will return foo
*
*/
export function findTokenOnLeftOfPosition(file: SourceFile, position: number): Node {
// Ideally, getTokenAtPosition should return a token. However, it is currently
// broken, so we do a check to make sure the result was indeed a token.
@@ -1334,7 +1334,7 @@ namespace ts {
name.charCodeAt(0) === name.charCodeAt(length - 1) &&
(name.charCodeAt(0) === CharacterCodes.doubleQuote || name.charCodeAt(0) === CharacterCodes.singleQuote)) {
return name.substring(1, length - 1);
};
}
return name;
}
@@ -1380,6 +1380,13 @@ namespace ts {
};
}
export function getFirstNonSpaceCharacterPosition(text: string, position: number) {
while (isWhiteSpace(text.charCodeAt(position))) {
position += 1;
}
return position;
}
export function getOpenBrace(constructor: ConstructorDeclaration, sourceFile: SourceFile) {
// First token is the open curly, this is where we want to put the 'super' call.
return constructor.body.getFirstToken(sourceFile);