-
Notifications
You must be signed in to change notification settings - Fork 13.2k
Fix ignore message indentation #22340
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
e51d0a7
b032bb3
ffc9c89
1b5629b
2e5bf36
9a8705b
81e6b84
f490227
acc0783
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,17 +9,17 @@ namespace ts.codefix { | |
| registerCodeFix({ | ||
| errorCodes, | ||
| getCodeActions(context) { | ||
| const { sourceFile, program, span } = context; | ||
| const { sourceFile, program, span, host, formatContext } = context; | ||
|
|
||
| if (!isInJavaScriptFile(sourceFile) || !isCheckJsEnabledForFile(sourceFile, program.getCompilerOptions())) { | ||
| return undefined; | ||
| } | ||
|
|
||
| const newLineCharacter = getNewLineOrDefaultFromHost(context.host, context.formatContext.options); | ||
| const newLineCharacter = getNewLineOrDefaultFromHost(host, formatContext.options); | ||
|
|
||
| return [{ | ||
| description: getLocaleSpecificMessage(Diagnostics.Ignore_this_error_message), | ||
| changes: [createFileTextChanges(sourceFile.fileName, [getIgnoreCommentLocationForLocation(sourceFile, span.start, newLineCharacter).change])], | ||
| changes: textChanges.ChangeTracker.with(context, t => makeChange(t, sourceFile, span.start, newLineCharacter)), | ||
| fixId, | ||
| }, | ||
| { | ||
|
|
@@ -33,36 +33,37 @@ namespace ts.codefix { | |
| }, | ||
| fixIds: [fixId], | ||
| getAllCodeActions: context => { | ||
| const seenLines = createMap<true>(); // Only need to add `// @ts-ignore` for a line once. | ||
| return codeFixAllWithTextChanges(context, errorCodes, (changes, err) => { | ||
| if (err.start !== undefined) { | ||
| const { lineNumber, change } = getIgnoreCommentLocationForLocation(err.file!, err.start, getNewLineOrDefaultFromHost(context.host, context.formatContext.options)); | ||
| if (addToSeen(seenLines, lineNumber)) { | ||
| changes.push(change); | ||
| } | ||
| } | ||
| }); | ||
| const newLineCharacter = getNewLineOrDefaultFromHost(context.host, context.formatContext.options); | ||
| const seenLines = createMap<true>(); | ||
| return codeFixAll(context, errorCodes, (changes, diag) => makeChange(changes, diag.file!, diag.start!, newLineCharacter, seenLines)); | ||
| }, | ||
| }); | ||
|
|
||
| function getIgnoreCommentLocationForLocation(sourceFile: SourceFile, position: number, newLineCharacter: string): { lineNumber: number, change: TextChange } { | ||
| function makeChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, position: number, newLineCharacter: string, seenLines?: Map<true>) { | ||
| if (isInComment(sourceFile, position) || isInString(sourceFile, position) || isInTemplateString(sourceFile, position)) { | ||
|
||
| return; | ||
| } | ||
|
|
||
| const { line: lineNumber } = getLineAndCharacterOfPosition(sourceFile, position); | ||
|
|
||
| // Only need to add `// @ts-ignore` for a line once. | ||
| if (seenLines && !addToSeen(seenLines, lineNumber)) { | ||
| return; | ||
| } | ||
|
|
||
| const lineStartPosition = getStartPositionOfLine(lineNumber, 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, /*includeJsDocComment*/ false); | ||
| const tokenLeadingComments = getLeadingCommentRangesOfNode(token, sourceFile); | ||
| if (!tokenLeadingComments || !tokenLeadingComments.length || tokenLeadingComments[0].pos >= startPosition) { | ||
| return { lineNumber, change: createTextChangeFromStartLength(startPosition, 0, `// @ts-ignore${newLineCharacter}`) }; | ||
| } | ||
| } | ||
| // If so, we do not want to separate the node from its comment if we can. | ||
| // Otherwise, add an extra new line immediately before the error span. | ||
| const insertAtLineStart = !isInComment(sourceFile, startPosition) && | ||
|
||
| !isInString(sourceFile, startPosition) && !isInTemplateString(sourceFile, startPosition); | ||
|
|
||
| // If all fails, add an extra new line immediately before the error span. | ||
| return { lineNumber, change: createTextChangeFromStartLength(position, 0, `${position === startPosition ? "" : newLineCharacter}// @ts-ignore${newLineCharacter}`) }; | ||
| const token = getTouchingToken(sourceFile, insertAtLineStart ? startPosition : position, /*includeJsDocComment*/ false); | ||
| const clone = setStartsOnNewLine(getSynthesizedDeepClone(token), true); | ||
| addSyntheticLeadingComment(clone, SyntaxKind.SingleLineCommentTrivia, " @ts-ignore"); | ||
| changes.replaceNode(sourceFile, token, clone, { preseveLeadingWhiteSpaces: true, prefix: insertAtLineStart ? undefined : newLineCharacter }); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -94,6 +94,10 @@ namespace ts.textChanges { | |
| * Text of inserted node will be formatted with this delta, otherwise delta will be inferred from the new node kind | ||
| */ | ||
| delta?: number; | ||
| /** | ||
| * Do not trim leading white spaces in the edit range | ||
| */ | ||
| preseveLeadingWhiteSpaces?: boolean; | ||
|
||
| } | ||
|
|
||
| enum ChangeKind { | ||
|
|
@@ -628,7 +632,7 @@ namespace ts.textChanges { | |
| ? change.nodes.map(n => removeSuffix(format(n), newLineCharacter)).join(newLineCharacter) | ||
| : format(change.node); | ||
| // strip initial indentation (spaces or tabs) if text will be inserted in the middle of the line | ||
| const noIndent = (options.indentation !== undefined || getLineStartPositionForPosition(pos, sourceFile) === pos) ? text : text.replace(/^\s+/, ""); | ||
| const noIndent = (options.preseveLeadingWhiteSpaces || options.indentation !== undefined || getLineStartPositionForPosition(pos, sourceFile) === pos) ? text : text.replace(/^\s+/, ""); | ||
| return (options.prefix || "") + noIndent + (options.suffix || ""); | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be neater if
changeshandled the newlines itself -- see discussion at #20574.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is the only place where we do something like this with comments. i did not make much sense to put it in the tracker.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could also make
changes.newLineCharacterpublic to avoid computing it yourself. There's no particular reason for it to be private if you want to handle newlines yourself in this use.