diff --git a/.changeset/four-papers-learn.md b/.changeset/four-papers-learn.md
new file mode 100644
index 000000000..f5838bc91
--- /dev/null
+++ b/.changeset/four-papers-learn.md
@@ -0,0 +1,5 @@
+---
+'svelte-language-server': patch
+---
+
+feat: quick fix for adding lang="ts"
diff --git a/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts b/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts
index 693c2581a..d7624cdf5 100644
--- a/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts
+++ b/packages/language-server/src/plugins/typescript/features/CodeActionsProvider.ts
@@ -59,6 +59,7 @@ import {
isTextSpanInGeneratedCode,
SnapshotMap
} from './utils';
+import { Node } from 'vscode-html-languageservice';
/**
* TODO change this to protocol constant if it's part of the protocol
@@ -701,10 +702,8 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
),
...this.getSvelteQuickFixes(
lang,
- document,
cannotFindNameDiagnostic,
tsDoc,
- formatCodeBasis,
userPreferences,
formatCodeSettings
)
@@ -760,8 +759,18 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
lang
);
+ const addLangCodeAction = this.getAddLangTSCodeAction(
+ document,
+ context,
+ tsDoc,
+ formatCodeBasis
+ );
+
// filter out empty code action
- return codeActionsNotFilteredOut.map(({ codeAction }) => codeAction).concat(fixAllActions);
+ const result = codeActionsNotFilteredOut
+ .map(({ codeAction }) => codeAction)
+ .concat(fixAllActions);
+ return addLangCodeAction ? [addLangCodeAction].concat(result) : result;
}
private async convertAndFixCodeFixAction({
@@ -1128,10 +1137,8 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
private getSvelteQuickFixes(
lang: ts.LanguageService,
- document: Document,
cannotFindNameDiagnostics: Diagnostic[],
tsDoc: DocumentSnapshot,
- formatCodeBasis: FormatCodeBasis,
userPreferences: ts.UserPreferences,
formatCodeSettings: ts.FormatCodeSettings
): CustomFixCannotFindNameInfo[] {
@@ -1141,14 +1148,10 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
return [];
}
- const typeChecker = program.getTypeChecker();
const results: CustomFixCannotFindNameInfo[] = [];
- const quote = getQuotePreference(sourceFile, userPreferences);
const getGlobalCompletion = memoize(() =>
lang.getCompletionsAtPosition(tsDoc.filePath, 0, userPreferences, formatCodeSettings)
);
- const [tsMajorStr] = ts.version.split('.');
- const tsSupportHandlerQuickFix = parseInt(tsMajorStr) >= 5;
for (const diagnostic of cannotFindNameDiagnostics) {
const identifier = this.findIdentifierForDiagnostic(tsDoc, diagnostic, sourceFile);
@@ -1173,24 +1176,6 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
);
}
- if (!tsSupportHandlerQuickFix) {
- const isQuickFixTargetEventHandler = this.isQuickFixForEventHandler(
- document,
- diagnostic
- );
- if (isQuickFixTargetEventHandler) {
- fixes.push(
- ...this.getEventHandlerQuickFixes(
- identifier,
- tsDoc,
- typeChecker,
- quote,
- formatCodeBasis
- )
- );
- }
- }
-
if (!fixes.length) {
continue;
}
@@ -1225,8 +1210,6 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
return identifier;
}
- // TODO: Remove this in late 2023
- // when most users have upgraded to TS 5.0+
private getSvelteStoreQuickFixes(
identifier: ts.Identifier,
lang: ts.LanguageService,
@@ -1275,101 +1258,121 @@ export class CodeActionsProviderImpl implements CodeActionsProvider {
return flatten(completion.entries.filter((c) => c.name === storeIdentifier).map(toFix));
}
- /**
- * Workaround for TypeScript doesn't provide a quick fix if the signature is typed as union type, like `(() => void) | null`
- * We can remove this once TypeScript doesn't have this limitation.
- */
- private getEventHandlerQuickFixes(
- identifier: ts.Identifier,
+ private getAddLangTSCodeAction(
+ document: Document,
+ context: CodeActionContext,
tsDoc: DocumentSnapshot,
- typeChecker: ts.TypeChecker,
- quote: string,
formatCodeBasis: FormatCodeBasis
- ): ts.CodeFixAction[] {
- const type = identifier && typeChecker.getContextualType(identifier);
+ ) {
+ if (tsDoc.scriptKind !== ts.ScriptKind.JS) {
+ return;
+ }
- // if it's not union typescript should be able to do it. no need to enhance
- if (!type || !type.isUnion()) {
- return [];
+ let hasTSOnlyDiagnostic = false;
+ for (const diagnostic of context.diagnostics) {
+ const num = Number(diagnostic.code);
+ const canOnlyBeUsedInTS = num >= 8004 && num <= 8017;
+ if (canOnlyBeUsedInTS) {
+ hasTSOnlyDiagnostic = true;
+ break;
+ }
+ }
+ if (!hasTSOnlyDiagnostic) {
+ return;
}
- const nonNullable = type.getNonNullableType();
+ if (!document.scriptInfo && !document.moduleScriptInfo) {
+ const hasNonTopLevelLang = document.html.roots.some((node) =>
+ this.hasLangTsScriptTag(node)
+ );
+ // Might be because issue with parsing the script tag, so don't suggest adding a new one
+ if (hasNonTopLevelLang) {
+ return;
+ }
- if (
- !(
- nonNullable.flags & ts.TypeFlags.Object &&
- (nonNullable as ts.ObjectType).objectFlags & ts.ObjectFlags.Anonymous
- )
- ) {
- return [];
+ return CodeAction.create(
+ 'Add ' + formatCodeBasis.newLine
+ }
+ ]
+ }
+ ]
+ },
+ CodeActionKind.QuickFix
+ );
}
- const signature = typeChecker.getSignaturesOfType(nonNullable, ts.SignatureKind.Call)[0];
+ const edits = [document.scriptInfo, document.moduleScriptInfo]
+ .map((info) => {
+ if (!info) {
+ return;
+ }
- const parameters = signature.parameters.map((p) => {
- const declaration = p.valueDeclaration ?? p.declarations?.[0];
- const typeString = declaration
- ? typeChecker.typeToString(typeChecker.getTypeOfSymbolAtLocation(p, declaration))
- : '';
+ const startTagNameEnd = document.positionAt(info.container.start + 7); // \n',
+ range: {
+ start: {
+ character: 0,
+ line: 0
+ },
+ end: {
+ character: 0,
+ line: 0
+ }
+ }
+ }
+ ],
+ textDocument: {
+ uri: getUri('codeaction-add-lang-ts-no-script.svelte'),
+ version: null
+ }
+ }
+ ]
+ }
+ }
+ ]);
+ });
});
diff --git a/packages/language-server/test/plugins/typescript/testfiles/code-actions/codeaction-add-lang-ts-no-script.svelte b/packages/language-server/test/plugins/typescript/testfiles/code-actions/codeaction-add-lang-ts-no-script.svelte
new file mode 100644
index 000000000..3a462a520
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/testfiles/code-actions/codeaction-add-lang-ts-no-script.svelte
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/language-server/test/plugins/typescript/testfiles/code-actions/codeaction-add-lang-ts.svelte b/packages/language-server/test/plugins/typescript/testfiles/code-actions/codeaction-add-lang-ts.svelte
new file mode 100644
index 000000000..0c39d5de6
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/testfiles/code-actions/codeaction-add-lang-ts.svelte
@@ -0,0 +1,7 @@
+
+
+
\ No newline at end of file
diff --git a/packages/svelte2tsx/package.json b/packages/svelte2tsx/package.json
index 15b242f11..833c8e36a 100644
--- a/packages/svelte2tsx/package.json
+++ b/packages/svelte2tsx/package.json
@@ -50,7 +50,7 @@
"build": "rollup -c",
"prepublishOnly": "npm run build",
"dev": "rollup -c -w",
- "test": "mocha test/test.ts"
+ "test": "mocha test/test.ts --no-experimental-strip-types"
},
"files": [
"index.mjs",