Skip to content

Commit

Permalink
(fix) add JSDoc before the export keyword in quick-fix (#1643)
Browse files Browse the repository at this point in the history
  • Loading branch information
jasonlyu123 authored Sep 19, 2022
1 parent 74cbde0 commit cd78438
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
CodeActionKind,
Diagnostic,
OptionalVersionedTextDocumentIdentifier,
Position,
Range,
TextDocumentEdit,
TextEdit,
Expand All @@ -15,6 +16,7 @@ import {
Document,
getLineAtPosition,
isAtEndOfLine,
isInTag,
isRangeInTag,
mapRangeToOriginal
} from '../../../lib/documents';
Expand Down Expand Up @@ -355,6 +357,14 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
);
}

if (fix.fixName === 'inferFromUsage') {
originalRange = this.checkAddJsDocCodeActionRange(
snapshot,
originalRange,
document
);
}

if (originalRange.start.line < 0 || originalRange.end.line < 0) {
return undefined;
}
Expand Down Expand Up @@ -666,18 +676,13 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
originalRange: Range,
document: Document,
edit: ts.TextChange
): TextEdit {
const startOffset = document.offsetAt(originalRange.start);
const text = document.getText();

// svetlte2tsx removes export in instance script
const insertedAfterExport = text.slice(0, startOffset).trim().endsWith('export');

if (!insertedAfterExport) {
return TextEdit.replace(originalRange, edit.newText);
): TextEdit | null {
if (!isInTag(originalRange.start, document.scriptInfo)) {
return null;
}

const position = document.positionAt(text.lastIndexOf('export', startOffset));
const position =
this.fixPropsCodeActionRange(originalRange.start, document) ?? originalRange.start;

// fix the length of trailing indent
const linesOfNewText = edit.newText.split('\n');
Expand All @@ -690,6 +695,56 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
return TextEdit.insert(position, linesOfNewText.join('\n'));
}

/**
* svelte2tsx removes export in instance script
*/
private fixPropsCodeActionRange(start: Position, document: Document): Position | undefined {
const documentText = document.getText();
const offset = document.offsetAt(start);
const exportKeywordOffset = documentText.lastIndexOf('export', offset);

// export let a;
if (
exportKeywordOffset < 0 ||
documentText.slice(exportKeywordOffset + 'export'.length, offset).trim()
) {
return;
}

const charBeforeExport = documentText[exportKeywordOffset - 1];
if (
(charBeforeExport !== undefined && !charBeforeExport.trim()) ||
charBeforeExport === ';'
) {
return document.positionAt(exportKeywordOffset);
}
}

private checkAddJsDocCodeActionRange(
snapshot: DocumentSnapshot,
originalRange: Range,
document: Document
): Range {
if (
snapshot.scriptKind !== ts.ScriptKind.JS &&
snapshot.scriptKind !== ts.ScriptKind.JSX &&
!isInTag(originalRange.start, document.scriptInfo)
) {
return originalRange;
}

const position = this.fixPropsCodeActionRange(originalRange.start, document);

if (position) {
return {
start: position,
end: position
};
}

return originalRange;
}

private async getLSAndTSDoc(document: Document) {
return this.lsAndTsDocResolver.getLSAndTSDoc(document);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,94 @@ function test(useNewTransformation: boolean) {
]);
});

it('provide quickfix for adding jsDoc type to props', async () => {
const { provider, document } = setup('codeaction-add-jsdoc.svelte');
const errorRange = Range.create(Position.create(7, 8), Position.create(7, 11));

const codeActions = await provider.getCodeActions(document, errorRange, {
diagnostics: [
{
code: 7034,
message:
"Variable 'abc' implicitly has type 'any' in some locations where its type cannot be determined.",
range: errorRange
}
]
});

const addJsDoc = codeActions.find(
(fix) => fix.title === "Infer type of 'abc' from usage"
);

(<TextDocumentEdit>addJsDoc?.edit?.documentChanges?.[0])?.edits.forEach(
(edit) => (edit.newText = harmonizeNewLines(edit.newText))
);

assert.deepStrictEqual(addJsDoc?.edit, {
documentChanges: [
<TextDocumentEdit>{
edits: [
{
newText: `/**\n${indent} * @type {any}\n${indent} */\n${indent}`,
range: {
start: { character: 4, line: 3 },
end: { character: 4, line: 3 }
}
}
],
textDocument: {
uri: getUri('codeaction-add-jsdoc.svelte'),
version: null
}
}
]
});
});

it('provide quickfix for adding jsDoc type to non props when props exist', async () => {
const { provider, document } = setup('codeaction-add-jsdoc.svelte');
const errorRange = Range.create(Position.create(9, 8), Position.create(9, 10));

const codeActions = await provider.getCodeActions(document, errorRange, {
diagnostics: [
{
code: 7034,
message:
"Variable 'ab' implicitly has type 'any' in some locations where its type cannot be determined.",
range: errorRange
}
]
});

const addJsDoc = codeActions.find(
(fix) => fix.title === "Infer type of 'ab' from usage"
);

(<TextDocumentEdit>addJsDoc?.edit?.documentChanges?.[0])?.edits.forEach(
(edit) => (edit.newText = harmonizeNewLines(edit.newText))
);

assert.deepStrictEqual(addJsDoc?.edit, {
documentChanges: [
<TextDocumentEdit>{
edits: [
{
newText: `/**\n${indent} * @type {any}\n${indent} */\n${indent}`,
range: {
start: { character: 4, line: 9 },
end: { character: 4, line: 9 }
}
}
],
textDocument: {
uri: getUri('codeaction-add-jsdoc.svelte'),
version: null
}
}
]
});
});

it('provides quickfix for component import', async () => {
const { provider, document } = setup('codeactions.svelte');

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script>
// @ts-check
export
let abc;
let ab;
</script>

{abc}
{ab}

0 comments on commit cd78438

Please sign in to comment.