mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into logical_assignment
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
const fixId = "fixIncorrectNamedTupleSyntax";
|
||||
const errorCodes = [
|
||||
Diagnostics.A_labeled_tuple_element_is_declared_as_optional_with_a_question_mark_after_the_name_and_before_the_colon_rather_than_after_the_type.code,
|
||||
Diagnostics.A_labeled_tuple_element_is_declared_as_rest_with_a_before_the_name_rather_than_before_the_type.code
|
||||
];
|
||||
|
||||
registerCodeFix({
|
||||
errorCodes,
|
||||
getCodeActions: context => {
|
||||
const { sourceFile, span } = context;
|
||||
const namedTupleMember = getNamedTupleMember(sourceFile, span.start);
|
||||
const changes = textChanges.ChangeTracker.with(context, t => doChange(t, sourceFile, namedTupleMember));
|
||||
return [createCodeFixAction(fixId, changes, Diagnostics.Move_labeled_tuple_element_modifiers_to_labels, fixId, Diagnostics.Move_labeled_tuple_element_modifiers_to_labels)];
|
||||
},
|
||||
fixIds: [fixId]
|
||||
});
|
||||
|
||||
function getNamedTupleMember(sourceFile: SourceFile, pos: number) {
|
||||
const token = getTokenAtPosition(sourceFile, pos);
|
||||
return findAncestor(token, t => t.kind === SyntaxKind.NamedTupleMember) as NamedTupleMember | undefined;
|
||||
}
|
||||
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, namedTupleMember?: NamedTupleMember) {
|
||||
if (!namedTupleMember) {
|
||||
return;
|
||||
}
|
||||
let unwrappedType = namedTupleMember.type;
|
||||
let sawOptional = false;
|
||||
let sawRest = false;
|
||||
while (unwrappedType.kind === SyntaxKind.OptionalType || unwrappedType.kind === SyntaxKind.RestType || unwrappedType.kind === SyntaxKind.ParenthesizedType) {
|
||||
if (unwrappedType.kind === SyntaxKind.OptionalType) {
|
||||
sawOptional = true;
|
||||
}
|
||||
else if (unwrappedType.kind === SyntaxKind.RestType) {
|
||||
sawRest = true;
|
||||
}
|
||||
unwrappedType = (unwrappedType as OptionalTypeNode | RestTypeNode | ParenthesizedTypeNode).type;
|
||||
}
|
||||
const updated = updateNamedTupleMember(
|
||||
namedTupleMember,
|
||||
namedTupleMember.dotDotDotToken || (sawRest ? createToken(SyntaxKind.DotDotDotToken) : undefined),
|
||||
namedTupleMember.name,
|
||||
namedTupleMember.questionToken || (sawOptional ? createToken(SyntaxKind.QuestionToken) : undefined),
|
||||
unwrappedType
|
||||
);
|
||||
if (updated === namedTupleMember) {
|
||||
return;
|
||||
}
|
||||
changes.replaceNode(sourceFile, namedTupleMember, updated);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ namespace ts.formatting {
|
||||
export interface FormatContext {
|
||||
readonly options: FormatCodeSettings;
|
||||
readonly getRules: RulesMap;
|
||||
readonly host: FormattingHost;
|
||||
}
|
||||
|
||||
export interface TextRangeWithKind<T extends SyntaxKind = SyntaxKind> extends TextRange {
|
||||
@@ -394,7 +395,7 @@ namespace ts.formatting {
|
||||
initialIndentation: number,
|
||||
delta: number,
|
||||
formattingScanner: FormattingScanner,
|
||||
{ options, getRules }: FormatContext,
|
||||
{ options, getRules, host }: FormatContext,
|
||||
requestKind: FormattingRequestKind,
|
||||
rangeContainsError: (r: TextRange) => boolean,
|
||||
sourceFile: SourceFileLike): TextChange[] {
|
||||
@@ -1193,7 +1194,7 @@ namespace ts.formatting {
|
||||
previousRange: TextRangeWithKind,
|
||||
previousStartLine: number,
|
||||
currentRange: TextRangeWithKind,
|
||||
currentStartLine: number,
|
||||
currentStartLine: number
|
||||
): LineAction {
|
||||
const onLaterLine = currentStartLine !== previousStartLine;
|
||||
switch (rule.action) {
|
||||
@@ -1221,7 +1222,7 @@ namespace ts.formatting {
|
||||
// edit should not be applied if we have one line feed between elements
|
||||
const lineDelta = currentStartLine - previousStartLine;
|
||||
if (lineDelta !== 1) {
|
||||
recordReplace(previousRange.end, currentRange.pos - previousRange.end, options.newLineCharacter!);
|
||||
recordReplace(previousRange.end, currentRange.pos - previousRange.end, getNewLineOrDefaultFromHost(host, options));
|
||||
return onLaterLine ? LineAction.None : LineAction.LineAdded;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* @internal */
|
||||
namespace ts.formatting {
|
||||
export function getFormatContext(options: FormatCodeSettings): FormatContext {
|
||||
return { options, getRules: getRulesMap() };
|
||||
export function getFormatContext(options: FormatCodeSettings, host: FormattingHost): FormatContext {
|
||||
return { options, getRules: getRulesMap(), host };
|
||||
}
|
||||
|
||||
let rulesMapCache: RulesMap | undefined;
|
||||
|
||||
@@ -574,7 +574,7 @@ namespace ts.formatting {
|
||||
return childKind !== SyntaxKind.JsxClosingFragment;
|
||||
case SyntaxKind.IntersectionType:
|
||||
case SyntaxKind.UnionType:
|
||||
if (childKind === SyntaxKind.TypeLiteral) {
|
||||
if (childKind === SyntaxKind.TypeLiteral || childKind === SyntaxKind.TupleType) {
|
||||
return false;
|
||||
}
|
||||
// falls through
|
||||
|
||||
@@ -42,6 +42,10 @@ namespace ts.OutliningElementsCollector {
|
||||
addOutliningForLeadingCommentsForNode(n.parent.parent.parent, sourceFile, cancellationToken, out);
|
||||
}
|
||||
|
||||
if (isFunctionLike(n) && isBinaryExpression(n.parent) && isPropertyAccessExpression(n.parent.left)) {
|
||||
addOutliningForLeadingCommentsForNode(n.parent.left, sourceFile, cancellationToken, out);
|
||||
}
|
||||
|
||||
const span = getOutliningSpanForNode(n, sourceFile);
|
||||
if (span) out.push(span);
|
||||
|
||||
|
||||
@@ -0,0 +1,219 @@
|
||||
/* @internal */
|
||||
namespace ts.refactor.addOrRemoveBracesToArrowFunction {
|
||||
const refactorName = "Convert overload list to single signature";
|
||||
const refactorDescription = Diagnostics.Convert_overload_list_to_single_signature.message;
|
||||
registerRefactor(refactorName, { getEditsForAction, getAvailableActions });
|
||||
|
||||
|
||||
function getAvailableActions(context: RefactorContext): readonly ApplicableRefactorInfo[] {
|
||||
const { file, startPosition, program } = context;
|
||||
const info = getConvertableOverloadListAtPosition(file, startPosition, program);
|
||||
if (!info) return emptyArray;
|
||||
|
||||
return [{
|
||||
name: refactorName,
|
||||
description: refactorDescription,
|
||||
actions: [{
|
||||
name: refactorName,
|
||||
description: refactorDescription
|
||||
}]
|
||||
}];
|
||||
}
|
||||
|
||||
function getEditsForAction(context: RefactorContext): RefactorEditInfo | undefined {
|
||||
const { file, startPosition, program } = context;
|
||||
const signatureDecls = getConvertableOverloadListAtPosition(file, startPosition, program);
|
||||
if (!signatureDecls) return undefined;
|
||||
|
||||
const checker = program.getTypeChecker();
|
||||
|
||||
const lastDeclaration = signatureDecls[signatureDecls.length - 1];
|
||||
let updated = lastDeclaration;
|
||||
switch (lastDeclaration.kind) {
|
||||
case SyntaxKind.MethodSignature: {
|
||||
updated = updateMethodSignature(
|
||||
lastDeclaration,
|
||||
lastDeclaration.typeParameters,
|
||||
getNewParametersForCombinedSignature(signatureDecls),
|
||||
lastDeclaration.type,
|
||||
lastDeclaration.name,
|
||||
lastDeclaration.questionToken
|
||||
);
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.MethodDeclaration: {
|
||||
updated = updateMethod(
|
||||
lastDeclaration,
|
||||
lastDeclaration.decorators,
|
||||
lastDeclaration.modifiers,
|
||||
lastDeclaration.asteriskToken,
|
||||
lastDeclaration.name,
|
||||
lastDeclaration.questionToken,
|
||||
lastDeclaration.typeParameters,
|
||||
getNewParametersForCombinedSignature(signatureDecls),
|
||||
lastDeclaration.type,
|
||||
lastDeclaration.body
|
||||
);
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.CallSignature: {
|
||||
updated = updateCallSignature(
|
||||
lastDeclaration,
|
||||
lastDeclaration.typeParameters,
|
||||
getNewParametersForCombinedSignature(signatureDecls),
|
||||
lastDeclaration.type,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.Constructor: {
|
||||
updated = updateConstructor(
|
||||
lastDeclaration,
|
||||
lastDeclaration.decorators,
|
||||
lastDeclaration.modifiers,
|
||||
getNewParametersForCombinedSignature(signatureDecls),
|
||||
lastDeclaration.body
|
||||
);
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.ConstructSignature: {
|
||||
updated = updateConstructSignature(
|
||||
lastDeclaration,
|
||||
lastDeclaration.typeParameters,
|
||||
getNewParametersForCombinedSignature(signatureDecls),
|
||||
lastDeclaration.type,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.FunctionDeclaration: {
|
||||
updated = updateFunctionDeclaration(
|
||||
lastDeclaration,
|
||||
lastDeclaration.decorators,
|
||||
lastDeclaration.modifiers,
|
||||
lastDeclaration.asteriskToken,
|
||||
lastDeclaration.name,
|
||||
lastDeclaration.typeParameters,
|
||||
getNewParametersForCombinedSignature(signatureDecls),
|
||||
lastDeclaration.type,
|
||||
lastDeclaration.body
|
||||
);
|
||||
break;
|
||||
}
|
||||
default: return Debug.failBadSyntaxKind(lastDeclaration, "Unhandled signature kind in overload list conversion refactoring");
|
||||
}
|
||||
|
||||
if (updated === lastDeclaration) {
|
||||
return; // No edits to apply, do nothing
|
||||
}
|
||||
|
||||
const edits = textChanges.ChangeTracker.with(context, t => {
|
||||
t.replaceNodeRange(file, signatureDecls[0], signatureDecls[signatureDecls.length - 1], updated);
|
||||
});
|
||||
|
||||
return { renameFilename: undefined, renameLocation: undefined, edits };
|
||||
|
||||
function getNewParametersForCombinedSignature(signatureDeclarations: (MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration)[]): NodeArray<ParameterDeclaration> {
|
||||
const lastSig = signatureDeclarations[signatureDeclarations.length - 1];
|
||||
if (isFunctionLikeDeclaration(lastSig) && lastSig.body) {
|
||||
// Trim away implementation signature arguments (they should already be compatible with overloads, but are likely less precise to guarantee compatability with the overloads)
|
||||
signatureDeclarations = signatureDeclarations.slice(0, signatureDeclarations.length - 1);
|
||||
}
|
||||
return createNodeArray([
|
||||
createParameter(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
createToken(SyntaxKind.DotDotDotToken),
|
||||
"args",
|
||||
/*questionToken*/ undefined,
|
||||
createUnionTypeNode(map(signatureDeclarations, convertSignatureParametersToTuple))
|
||||
)
|
||||
]);
|
||||
}
|
||||
|
||||
function convertSignatureParametersToTuple(decl: MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration): TupleTypeNode {
|
||||
const members = map(decl.parameters, convertParameterToNamedTupleMember);
|
||||
return setEmitFlags(createTupleTypeNode(members), some(members, m => !!length(getSyntheticLeadingComments(m))) ? EmitFlags.None : EmitFlags.SingleLine);
|
||||
}
|
||||
|
||||
function convertParameterToNamedTupleMember(p: ParameterDeclaration): NamedTupleMember {
|
||||
Debug.assert(isIdentifier(p.name)); // This is checked during refactoring applicability checking
|
||||
const result = setTextRange(createNamedTupleMember(
|
||||
p.dotDotDotToken,
|
||||
p.name,
|
||||
p.questionToken,
|
||||
p.type || createKeywordTypeNode(SyntaxKind.AnyKeyword)
|
||||
), p);
|
||||
const parameterDocComment = p.symbol && p.symbol.getDocumentationComment(checker);
|
||||
if (parameterDocComment) {
|
||||
const newComment = displayPartsToString(parameterDocComment);
|
||||
if (newComment.length) {
|
||||
setSyntheticLeadingComments(result, [{
|
||||
text: `*
|
||||
${newComment.split("\n").map(c => ` * ${c}`).join("\n")}
|
||||
`,
|
||||
kind: SyntaxKind.MultiLineCommentTrivia,
|
||||
pos: -1,
|
||||
end: -1,
|
||||
hasTrailingNewLine: true,
|
||||
hasLeadingNewline: true,
|
||||
}]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function isConvertableSignatureDeclaration(d: Node): d is MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration {
|
||||
switch (d.kind) {
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getConvertableOverloadListAtPosition(file: SourceFile, startPosition: number, program: Program) {
|
||||
const node = getTokenAtPosition(file, startPosition);
|
||||
const containingDecl = findAncestor(node, isConvertableSignatureDeclaration);
|
||||
if (!containingDecl) {
|
||||
return;
|
||||
}
|
||||
const checker = program.getTypeChecker();
|
||||
const signatureSymbol = containingDecl.symbol;
|
||||
if (!signatureSymbol) {
|
||||
return;
|
||||
}
|
||||
const decls = signatureSymbol.declarations;
|
||||
if (length(decls) <= 1) {
|
||||
return;
|
||||
}
|
||||
if (!every(decls, d => getSourceFileOfNode(d) === file)) {
|
||||
return;
|
||||
}
|
||||
if (!isConvertableSignatureDeclaration(decls[0])) {
|
||||
return;
|
||||
}
|
||||
const kindOne = decls[0].kind;
|
||||
if (!every(decls, d => d.kind === kindOne)) {
|
||||
return;
|
||||
}
|
||||
const signatureDecls = decls as (MethodSignature | MethodDeclaration | CallSignatureDeclaration | ConstructorDeclaration | ConstructSignatureDeclaration | FunctionDeclaration)[];
|
||||
if (some(signatureDecls, d => !!d.typeParameters || some(d.parameters, p => !!p.decorators || !!p.modifiers || !isIdentifier(p.name)))) {
|
||||
return;
|
||||
}
|
||||
const signatures = mapDefined(signatureDecls, d => checker.getSignatureFromDeclaration(d));
|
||||
if (length(signatures) !== length(decls)) {
|
||||
return;
|
||||
}
|
||||
const returnOne = checker.getReturnTypeOfSignature(signatures[0]);
|
||||
if (!every(signatures, s => checker.getReturnTypeOfSignature(s) === returnOne)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return signatureDecls;
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ namespace ts.refactor.extractSymbol {
|
||||
const usedConstantNames: Map<boolean> = createMap();
|
||||
|
||||
let i = 0;
|
||||
for (const {functionExtraction, constantExtraction} of extractions) {
|
||||
for (const { functionExtraction, constantExtraction } of extractions) {
|
||||
// Skip these since we don't have a way to report errors yet
|
||||
if (functionExtraction.errors.length === 0) {
|
||||
// Don't issue refactorings with duplicated names.
|
||||
@@ -1103,7 +1103,12 @@ namespace ts.refactor.extractSymbol {
|
||||
changeTracker.delete(context.file, node.parent);
|
||||
}
|
||||
else {
|
||||
const localReference = createIdentifier(localNameText);
|
||||
let localReference: Expression = createIdentifier(localNameText);
|
||||
// When extract to a new variable in JSX content, need to wrap a {} out of the new variable
|
||||
// or it will become a plain text
|
||||
if (isInJSXContent(node)) {
|
||||
localReference = createJsxExpression(/*dotDotDotToken*/ undefined, localReference);
|
||||
}
|
||||
changeTracker.replaceNode(context.file, node, localReference);
|
||||
}
|
||||
}
|
||||
@@ -1115,6 +1120,12 @@ namespace ts.refactor.extractSymbol {
|
||||
const renameLocation = getRenameLocation(edits, renameFilename, localNameText, /*isDeclaredBeforeUse*/ true);
|
||||
return { renameFilename, renameLocation, edits };
|
||||
|
||||
function isInJSXContent(node: Node) {
|
||||
if (!isJsxElement(node)) return false;
|
||||
if (isJsxElement(node.parent)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function transformFunctionInitializerAndType(variableType: TypeNode | undefined, initializer: Expression): { variableType: TypeNode | undefined, initializer: Expression } {
|
||||
// If no contextual type exists there is nothing to transfer to the function signature
|
||||
if (variableType === undefined) return { variableType, initializer };
|
||||
@@ -1215,8 +1226,8 @@ namespace ts.refactor.extractSymbol {
|
||||
}
|
||||
|
||||
function compareTypesByDeclarationOrder(
|
||||
{type: type1, declaration: declaration1}: {type: Type, declaration?: Declaration},
|
||||
{type: type2, declaration: declaration2}: {type: Type, declaration?: Declaration}) {
|
||||
{ type: type1, declaration: declaration1 }: { type: Type, declaration?: Declaration },
|
||||
{ type: type2, declaration: declaration2 }: { type: Type, declaration?: Declaration }) {
|
||||
|
||||
return compareProperties(declaration1, declaration2, "pos", compareValues)
|
||||
|| compareStringsCaseSensitive(
|
||||
@@ -1621,7 +1632,7 @@ namespace ts.refactor.extractSymbol {
|
||||
// a lot of properties, each of which the walker will visit. Unfortunately, the
|
||||
// solution isn't as trivial as filtering to user types because of (e.g.) Array.
|
||||
const symbolWalker = checker.getSymbolWalker(() => (cancellationToken.throwIfCancellationRequested(), true));
|
||||
const {visitedTypes} = symbolWalker.walkType(type);
|
||||
const { visitedTypes } = symbolWalker.walkType(type);
|
||||
|
||||
for (const visitedType of visitedTypes) {
|
||||
if (visitedType.isTypeParameter()) {
|
||||
|
||||
@@ -145,6 +145,11 @@ namespace ts.refactor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (file && isTupleTypeNode(node) && (getLineAndCharacterOfPosition(file, node.pos).line === getLineAndCharacterOfPosition(file, node.end).line)) {
|
||||
setEmitFlags(node, EmitFlags.SingleLine);
|
||||
}
|
||||
|
||||
return forEachChild(node, visitor);
|
||||
}
|
||||
}
|
||||
|
||||
+17
-10
@@ -328,7 +328,14 @@ namespace ts {
|
||||
getDocumentationComment(checker: TypeChecker | undefined): SymbolDisplayPart[] {
|
||||
if (!this.documentationComment) {
|
||||
this.documentationComment = emptyArray; // Set temporarily to avoid an infinite loop finding inherited docs
|
||||
this.documentationComment = getDocumentationComment(this.declarations, checker);
|
||||
|
||||
if (!this.declarations && (this as Symbol as TransientSymbol).target && ((this as Symbol as TransientSymbol).target as TransientSymbol).tupleLabelDeclaration) {
|
||||
const labelDecl = ((this as Symbol as TransientSymbol).target as TransientSymbol).tupleLabelDeclaration!;
|
||||
this.documentationComment = getDocumentationComment([labelDecl], checker);
|
||||
}
|
||||
else {
|
||||
this.documentationComment = getDocumentationComment(this.declarations, checker);
|
||||
}
|
||||
}
|
||||
return this.documentationComment;
|
||||
}
|
||||
@@ -1502,7 +1509,7 @@ namespace ts {
|
||||
position,
|
||||
{ name, source },
|
||||
host,
|
||||
(formattingOptions && formatting.getFormatContext(formattingOptions))!, // TODO: GH#18217
|
||||
(formattingOptions && formatting.getFormatContext(formattingOptions, host))!, // TODO: GH#18217
|
||||
preferences,
|
||||
cancellationToken,
|
||||
);
|
||||
@@ -1840,16 +1847,16 @@ namespace ts {
|
||||
|
||||
function getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions | FormatCodeSettings): TextChange[] {
|
||||
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
||||
return formatting.formatSelection(start, end, sourceFile, formatting.getFormatContext(toEditorSettings(options)));
|
||||
return formatting.formatSelection(start, end, sourceFile, formatting.getFormatContext(toEditorSettings(options), host));
|
||||
}
|
||||
|
||||
function getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[] {
|
||||
return formatting.formatDocument(syntaxTreeCache.getCurrentSourceFile(fileName), formatting.getFormatContext(toEditorSettings(options)));
|
||||
return formatting.formatDocument(syntaxTreeCache.getCurrentSourceFile(fileName), formatting.getFormatContext(toEditorSettings(options), host));
|
||||
}
|
||||
|
||||
function getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions | FormatCodeSettings): TextChange[] {
|
||||
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
||||
const formatContext = formatting.getFormatContext(toEditorSettings(options));
|
||||
const formatContext = formatting.getFormatContext(toEditorSettings(options), host);
|
||||
|
||||
if (!isInComment(sourceFile, position)) {
|
||||
switch (key) {
|
||||
@@ -1871,7 +1878,7 @@ namespace ts {
|
||||
synchronizeHostData();
|
||||
const sourceFile = getValidSourceFile(fileName);
|
||||
const span = createTextSpanFromBounds(start, end);
|
||||
const formatContext = formatting.getFormatContext(formatOptions);
|
||||
const formatContext = formatting.getFormatContext(formatOptions, host);
|
||||
|
||||
return flatMap(deduplicate<number>(errorCodes, equateValues, compareValues), errorCode => {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
@@ -1883,7 +1890,7 @@ namespace ts {
|
||||
synchronizeHostData();
|
||||
Debug.assert(scope.type === "file");
|
||||
const sourceFile = getValidSourceFile(scope.fileName);
|
||||
const formatContext = formatting.getFormatContext(formatOptions);
|
||||
const formatContext = formatting.getFormatContext(formatOptions, host);
|
||||
|
||||
return codefix.getAllFixes({ fixId, sourceFile, program, host, cancellationToken, formatContext, preferences });
|
||||
}
|
||||
@@ -1892,13 +1899,13 @@ namespace ts {
|
||||
synchronizeHostData();
|
||||
Debug.assert(scope.type === "file");
|
||||
const sourceFile = getValidSourceFile(scope.fileName);
|
||||
const formatContext = formatting.getFormatContext(formatOptions);
|
||||
const formatContext = formatting.getFormatContext(formatOptions, host);
|
||||
|
||||
return OrganizeImports.organizeImports(sourceFile, formatContext, host, program, preferences);
|
||||
}
|
||||
|
||||
function getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences = emptyOptions): readonly FileTextChanges[] {
|
||||
return ts.getEditsForFileRename(getProgram()!, oldFilePath, newFilePath, host, formatting.getFormatContext(formatOptions), preferences, sourceMapper);
|
||||
return ts.getEditsForFileRename(getProgram()!, oldFilePath, newFilePath, host, formatting.getFormatContext(formatOptions, host), preferences, sourceMapper);
|
||||
}
|
||||
|
||||
function applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult>;
|
||||
@@ -2141,7 +2148,7 @@ namespace ts {
|
||||
endPosition,
|
||||
program: getProgram()!,
|
||||
host,
|
||||
formatContext: formatting.getFormatContext(formatOptions!), // TODO: GH#18217
|
||||
formatContext: formatting.getFormatContext(formatOptions!, host), // TODO: GH#18217
|
||||
cancellationToken,
|
||||
preferences,
|
||||
};
|
||||
|
||||
@@ -500,16 +500,37 @@ namespace ts.SignatureHelp {
|
||||
const enclosingDeclaration = getEnclosingDeclarationFromInvocation(invocation);
|
||||
const callTargetSymbol = invocation.kind === InvocationKind.Contextual ? invocation.symbol : typeChecker.getSymbolAtLocation(getExpressionFromInvocation(invocation));
|
||||
const callTargetDisplayParts = callTargetSymbol ? symbolToDisplayParts(typeChecker, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined) : emptyArray;
|
||||
const items = candidates.map(candidateSignature => getSignatureHelpItem(candidateSignature, callTargetDisplayParts, isTypeParameterList, typeChecker, enclosingDeclaration, sourceFile));
|
||||
const items = map(candidates, candidateSignature => getSignatureHelpItem(candidateSignature, callTargetDisplayParts, isTypeParameterList, typeChecker, enclosingDeclaration, sourceFile));
|
||||
|
||||
if (argumentIndex !== 0) {
|
||||
Debug.assertLessThan(argumentIndex, argumentCount);
|
||||
}
|
||||
|
||||
const selectedItemIndex = candidates.indexOf(resolvedSignature);
|
||||
let selectedItemIndex = 0;
|
||||
let itemsSeen = 0;
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
if (candidates[i] === resolvedSignature) {
|
||||
selectedItemIndex = itemsSeen;
|
||||
if (item.length > 1) {
|
||||
// check to see if any items in the list better match than the first one, as the checker isn't filtering the nested lists
|
||||
// (those come from tuple parameter expansion)
|
||||
let count = 0;
|
||||
for (const i of item) {
|
||||
if (i.isVariadic || i.parameters.length >= argumentCount) {
|
||||
selectedItemIndex = itemsSeen + count;
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
itemsSeen += item.length;
|
||||
}
|
||||
|
||||
Debug.assert(selectedItemIndex !== -1); // If candidates is non-empty it should always include bestSignature. We check for an empty candidates before calling this function.
|
||||
|
||||
return { items, applicableSpan, selectedItemIndex, argumentIndex, argumentCount };
|
||||
return { items: flatMapToMutable(items, identity), applicableSpan, selectedItemIndex, argumentIndex, argumentCount };
|
||||
}
|
||||
|
||||
function createTypeHelpItems(
|
||||
@@ -538,13 +559,15 @@ namespace ts.SignatureHelp {
|
||||
|
||||
const separatorDisplayParts: SymbolDisplayPart[] = [punctuationPart(SyntaxKind.CommaToken), spacePart()];
|
||||
|
||||
function getSignatureHelpItem(candidateSignature: Signature, callTargetDisplayParts: readonly SymbolDisplayPart[], isTypeParameterList: boolean, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem {
|
||||
const { isVariadic, parameters, prefix, suffix } = (isTypeParameterList ? itemInfoForTypeParameters : itemInfoForParameters)(candidateSignature, checker, enclosingDeclaration, sourceFile);
|
||||
const prefixDisplayParts = [...callTargetDisplayParts, ...prefix];
|
||||
const suffixDisplayParts = [...suffix, ...returnTypeToDisplayParts(candidateSignature, enclosingDeclaration, checker)];
|
||||
const documentation = candidateSignature.getDocumentationComment(checker);
|
||||
const tags = candidateSignature.getJsDocTags();
|
||||
return { isVariadic, prefixDisplayParts, suffixDisplayParts, separatorDisplayParts, parameters, documentation, tags };
|
||||
function getSignatureHelpItem(candidateSignature: Signature, callTargetDisplayParts: readonly SymbolDisplayPart[], isTypeParameterList: boolean, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem[] {
|
||||
const infos = (isTypeParameterList ? itemInfoForTypeParameters : itemInfoForParameters)(candidateSignature, checker, enclosingDeclaration, sourceFile);
|
||||
return map(infos, ({ isVariadic, parameters, prefix, suffix }) => {
|
||||
const prefixDisplayParts = [...callTargetDisplayParts, ...prefix];
|
||||
const suffixDisplayParts = [...suffix, ...returnTypeToDisplayParts(candidateSignature, enclosingDeclaration, checker)];
|
||||
const documentation = candidateSignature.getDocumentationComment(checker);
|
||||
const tags = candidateSignature.getJsDocTags();
|
||||
return { isVariadic, prefixDisplayParts, suffixDisplayParts, separatorDisplayParts, parameters, documentation, tags };
|
||||
});
|
||||
}
|
||||
|
||||
function returnTypeToDisplayParts(candidateSignature: Signature, enclosingDeclaration: Node, checker: TypeChecker): readonly SymbolDisplayPart[] {
|
||||
@@ -563,19 +586,22 @@ namespace ts.SignatureHelp {
|
||||
|
||||
interface SignatureHelpItemInfo { readonly isVariadic: boolean; readonly parameters: SignatureHelpParameter[]; readonly prefix: readonly SymbolDisplayPart[]; readonly suffix: readonly SymbolDisplayPart[]; }
|
||||
|
||||
function itemInfoForTypeParameters(candidateSignature: Signature, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItemInfo {
|
||||
function itemInfoForTypeParameters(candidateSignature: Signature, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItemInfo[] {
|
||||
const typeParameters = (candidateSignature.target || candidateSignature).typeParameters;
|
||||
const printer = createPrinter({ removeComments: true });
|
||||
const parameters = (typeParameters || emptyArray).map(t => createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer));
|
||||
const parameterParts = mapToDisplayParts(writer => {
|
||||
const thisParameter = candidateSignature.thisParameter ? [checker.symbolToParameterDeclaration(candidateSignature.thisParameter, enclosingDeclaration, signatureHelpNodeBuilderFlags)!] : [];
|
||||
const params = createNodeArray([...thisParameter, ...checker.getExpandedParameters(candidateSignature).map(param => checker.symbolToParameterDeclaration(param, enclosingDeclaration, signatureHelpNodeBuilderFlags)!)]);
|
||||
printer.writeList(ListFormat.CallExpressionArguments, params, sourceFile, writer);
|
||||
const thisParameter = candidateSignature.thisParameter ? [checker.symbolToParameterDeclaration(candidateSignature.thisParameter, enclosingDeclaration, signatureHelpNodeBuilderFlags)!] : [];
|
||||
|
||||
return checker.getExpandedParameters(candidateSignature).map(paramList => {
|
||||
const params = createNodeArray([...thisParameter, ...map(paramList, param => checker.symbolToParameterDeclaration(param, enclosingDeclaration, signatureHelpNodeBuilderFlags)!)]);
|
||||
const parameterParts = mapToDisplayParts(writer => {
|
||||
printer.writeList(ListFormat.CallExpressionArguments, params, sourceFile, writer);
|
||||
});
|
||||
return { isVariadic: false, parameters, prefix: [punctuationPart(SyntaxKind.LessThanToken)], suffix: [punctuationPart(SyntaxKind.GreaterThanToken), ...parameterParts] };
|
||||
});
|
||||
return { isVariadic: false, parameters, prefix: [punctuationPart(SyntaxKind.LessThanToken)], suffix: [punctuationPart(SyntaxKind.GreaterThanToken), ...parameterParts] };
|
||||
}
|
||||
|
||||
function itemInfoForParameters(candidateSignature: Signature, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItemInfo {
|
||||
function itemInfoForParameters(candidateSignature: Signature, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItemInfo[] {
|
||||
const isVariadic = checker.hasEffectiveRestParameter(candidateSignature);
|
||||
const printer = createPrinter({ removeComments: true });
|
||||
const typeParameterParts = mapToDisplayParts(writer => {
|
||||
@@ -584,8 +610,15 @@ namespace ts.SignatureHelp {
|
||||
printer.writeList(ListFormat.TypeParameters, args, sourceFile, writer);
|
||||
}
|
||||
});
|
||||
const parameters = checker.getExpandedParameters(candidateSignature).map(p => createSignatureHelpParameterForParameter(p, checker, enclosingDeclaration, sourceFile, printer));
|
||||
return { isVariadic, parameters, prefix: [...typeParameterParts, punctuationPart(SyntaxKind.OpenParenToken)], suffix: [punctuationPart(SyntaxKind.CloseParenToken)] };
|
||||
const lists = checker.getExpandedParameters(candidateSignature);
|
||||
return lists.map(parameterList => {
|
||||
return {
|
||||
isVariadic: isVariadic && (lists.length === 1 || !!((parameterList[parameterList.length - 1] as TransientSymbol).checkFlags & CheckFlags.RestParameter)),
|
||||
parameters: parameterList.map(p => createSignatureHelpParameterForParameter(p, checker, enclosingDeclaration, sourceFile, printer)),
|
||||
prefix: [...typeParameterParts, punctuationPart(SyntaxKind.OpenParenToken)],
|
||||
suffix: [punctuationPart(SyntaxKind.CloseParenToken)]
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function createSignatureHelpParameterForParameter(parameter: Symbol, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile, printer: Printer): SignatureHelpParameter {
|
||||
|
||||
@@ -481,6 +481,14 @@ namespace ts.SymbolDisplay {
|
||||
else {
|
||||
addRange(displayParts, typeToDisplayParts(typeChecker, type, enclosingDeclaration));
|
||||
}
|
||||
if ((symbol as TransientSymbol).target && ((symbol as TransientSymbol).target as TransientSymbol).tupleLabelDeclaration) {
|
||||
const labelDecl = ((symbol as TransientSymbol).target as TransientSymbol).tupleLabelDeclaration!;
|
||||
Debug.assertNode(labelDecl.name, isIdentifier);
|
||||
displayParts.push(spacePart());
|
||||
displayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
|
||||
displayParts.push(textPart(idText(labelDecl.name)));
|
||||
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
|
||||
}
|
||||
}
|
||||
else if (symbolFlags & SymbolFlags.Function ||
|
||||
symbolFlags & SymbolFlags.Method ||
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
"codefixes/fixClassIncorrectlyImplementsInterface.ts",
|
||||
"codefixes/importFixes.ts",
|
||||
"codefixes/fixImplicitThis.ts",
|
||||
"codefixes/fixIncorrectNamedTupleSyntax.ts",
|
||||
"codefixes/fixSpelling.ts",
|
||||
"codefixes/returnValueCorrect.ts",
|
||||
"codefixes/fixAddMissingMember.ts",
|
||||
@@ -101,6 +102,7 @@
|
||||
"codefixes/fixExpectedComma.ts",
|
||||
"refactors/convertExport.ts",
|
||||
"refactors/convertImport.ts",
|
||||
"refactors/convertOverloadListToSingleSignature.ts",
|
||||
"refactors/extractSymbol.ts",
|
||||
"refactors/extractType.ts",
|
||||
"refactors/generateGetAccessorAndSetAccessor.ts",
|
||||
|
||||
@@ -203,6 +203,11 @@ namespace ts {
|
||||
has(dependencyName: string, inGroups?: PackageJsonDependencyGroup): boolean;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface FormattingHost {
|
||||
getNewLine?(): string;
|
||||
}
|
||||
|
||||
//
|
||||
// Public interface of the host of a language service instance.
|
||||
//
|
||||
|
||||
@@ -2085,9 +2085,9 @@ namespace ts {
|
||||
/**
|
||||
* The default is CRLF.
|
||||
*/
|
||||
export function getNewLineOrDefaultFromHost(host: LanguageServiceHost | LanguageServiceShimHost, formatSettings?: FormatCodeSettings) {
|
||||
return (formatSettings && formatSettings.newLineCharacter) ||
|
||||
(host.getNewLine && host.getNewLine()) ||
|
||||
export function getNewLineOrDefaultFromHost(host: FormattingHost, formatSettings?: FormatCodeSettings) {
|
||||
return formatSettings?.newLineCharacter ||
|
||||
host.getNewLine?.() ||
|
||||
carriageReturnLineFeed;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user