diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index c741138d9..17143b2ab 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -23,6 +23,31 @@ jobs:
env:
CI: true
+ test-svelte5:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ - uses: pnpm/action-setup@v2.2.4
+ - uses: actions/setup-node@v3
+ with:
+ node-version: "18.x"
+ cache: pnpm
+
+ # Lets us use one-liner JSON manipulations the package.json files
+ - run: "npm install -g json"
+
+ # Get projects set up
+ - run: json -I -f package.json -e 'this.pnpm={"overrides":{"svelte":"^5.0.0-next.100"}}'
+ - run: pnpm install --no-frozen-lockfile
+ - run: pnpm bootstrap
+ - run: pnpm build
+
+ # Run any tests
+ - run: pnpm test
+ env:
+ CI: true
+
lint:
runs-on: ubuntu-latest
diff --git a/packages/language-server/src/plugins/svelte/features/getDiagnostics.ts b/packages/language-server/src/plugins/svelte/features/getDiagnostics.ts
index dbc21bfb8..4c1f91d7a 100644
--- a/packages/language-server/src/plugins/svelte/features/getDiagnostics.ts
+++ b/packages/language-server/src/plugins/svelte/features/getDiagnostics.ts
@@ -63,7 +63,7 @@ async function tryGetDiagnostics(
if (cancellationToken?.isCancellationRequested) {
return [];
}
- return (((res.stats as any)?.warnings || res.warnings || []) as Warning[])
+ return (res.warnings || [])
.filter((warning) => settings[warning.code] !== 'ignore')
.map((warning) => {
const start = warning.start || { line: 1, column: 0 };
diff --git a/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts b/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts
index 5f243b13e..d5d921af5 100644
--- a/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts
+++ b/packages/language-server/src/plugins/typescript/DocumentSnapshot.ts
@@ -87,6 +87,7 @@ export namespace DocumentSnapshot {
document,
parserError,
scriptKind,
+ options.version,
text,
nrPrependedLines,
exportedNames,
@@ -272,6 +273,7 @@ export class SvelteDocumentSnapshot implements DocumentSnapshot {
public readonly parent: Document,
public readonly parserError: ParserError | null,
public readonly scriptKind: ts.ScriptKind,
+ public readonly svelteVersion: string | undefined,
private readonly text: string,
private readonly nrPrependedLines: number,
private readonly exportedNames: IExportedNames,
@@ -279,6 +281,10 @@ export class SvelteDocumentSnapshot implements DocumentSnapshot {
private readonly htmlAst?: TemplateNode
) {}
+ get isSvelte5Plus() {
+ return Number(this.svelteVersion?.split('.')[0]) >= 5;
+ }
+
get filePath() {
return this.parent.getFilePath() || '';
}
diff --git a/packages/language-server/src/plugins/typescript/features/DiagnosticsProvider.ts b/packages/language-server/src/plugins/typescript/features/DiagnosticsProvider.ts
index 64223ac35..485b041f2 100644
--- a/packages/language-server/src/plugins/typescript/features/DiagnosticsProvider.ts
+++ b/packages/language-server/src/plugins/typescript/features/DiagnosticsProvider.ts
@@ -21,7 +21,14 @@ import {
isStoreVariableIn$storeDeclaration,
get$storeOffsetOf$storeDeclaration
} from './utils';
-import { not, flatten, passMap, swapRangeStartEndIfNecessary, memoize } from '../../../utils';
+import {
+ not,
+ flatten,
+ passMap,
+ swapRangeStartEndIfNecessary,
+ memoize,
+ traverseTypeString
+} from '../../../utils';
import { LSConfigManager } from '../../../ls-config';
import { isAttributeName, isEventHandler } from '../svelte-ast-utils';
@@ -37,7 +44,10 @@ export enum DiagnosticCode {
DUPLICATED_JSX_ATTRIBUTES = 17001, // "JSX elements cannot have multiple attributes with the same name."
DUPLICATE_IDENTIFIER = 2300, // "Duplicate identifier 'xxx'"
MULTIPLE_PROPS_SAME_NAME = 1117, // "An object literal cannot have multiple properties with the same name in strict mode."
- TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y = 2345, // "Argument of type '..' is not assignable to parameter of type '..'."
+ ARG_TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y = 2345, // "Argument of type '..' is not assignable to parameter of type '..'."
+ TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y = 2322, // "Type '..' is not assignable to type '..'."
+ TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y_DID_YOU_MEAN = 2820, // "Type '..' is not assignable to type '..'. Did you mean '...'?"
+ UNKNOWN_PROP = 2353, // "Object literal may only specify known properties, and '...' does not exist in type '...'"
MISSING_PROPS = 2739, // "Type '...' is missing the following properties from type '..': ..."
MISSING_PROP = 2741, // "Property '..' is missing in type '..' but required in type '..'."
NO_OVERLOAD_MATCHES_CALL = 2769, // "No overload matches this call"
@@ -101,7 +111,7 @@ export class DiagnosticsProviderImpl implements DiagnosticsProvider {
for (const diagnostic of diagnostics) {
if (
(diagnostic.code === DiagnosticCode.NO_OVERLOAD_MATCHES_CALL ||
- diagnostic.code === DiagnosticCode.TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y) &&
+ diagnostic.code === DiagnosticCode.ARG_TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y) &&
!notGenerated(diagnostic)
) {
if (isStoreVariableIn$storeDeclaration(tsDoc.getFullText(), diagnostic.start!)) {
@@ -147,7 +157,7 @@ export class DiagnosticsProviderImpl implements DiagnosticsProvider {
.map(mapRange(tsDoc, document, lang))
.filter(hasNoNegativeLines)
.filter(isNoFalsePositive(document, tsDoc))
- .map(enhanceIfNecessary)
+ .map(adjustIfNecessary)
.map(swapDiagRangeStartEndIfNecessary);
}
@@ -180,9 +190,11 @@ function mapRange(
}
if (
- [DiagnosticCode.MISSING_PROP, DiagnosticCode.MISSING_PROPS].includes(
+ ([DiagnosticCode.MISSING_PROP, DiagnosticCode.MISSING_PROPS].includes(
diagnostic.code as number
- ) &&
+ ) ||
+ (DiagnosticCode.TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y &&
+ diagnostic.message.includes("'PropsWithChildren<"))) &&
!hasNonZeroRange({ range })
) {
const node = getNodeIfIsInStartTag(document.html, document.offsetAt(range.start));
@@ -286,11 +298,11 @@ function isNoUsedBeforeAssigned(
}
/**
- * Some diagnostics have JSX-specific nomenclature. Enhance them for more clarity.
+ * Some diagnostics have JSX-specific or confusing nomenclature. Enhance/adjust them for more clarity.
*/
-function enhanceIfNecessary(diagnostic: Diagnostic): Diagnostic {
+function adjustIfNecessary(diagnostic: Diagnostic): Diagnostic {
if (
- diagnostic.code === DiagnosticCode.TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y &&
+ diagnostic.code === DiagnosticCode.ARG_TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y &&
diagnostic.message.includes('ConstructorOfATypedSvelteComponent')
) {
return {
@@ -315,6 +327,37 @@ function enhanceIfNecessary(diagnostic: Diagnostic): Diagnostic {
};
}
+ if (
+ (diagnostic.code === DiagnosticCode.TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y ||
+ diagnostic.code === DiagnosticCode.TYPE_X_NOT_ASSIGNABLE_TO_TYPE_Y_DID_YOU_MEAN) &&
+ diagnostic.message.includes("'Bindable<")
+ ) {
+ const countBindable = (diagnostic.message.match(/'Bindable\ from diagnostic message
+ const start = diagnostic.message.indexOf("'Bindable<");
+ const startType = start + "'Bindable".length;
+ const end = traverseTypeString(diagnostic.message, startType, '>');
+ diagnostic.message =
+ diagnostic.message.substring(0, start + 1) +
+ diagnostic.message.substring(startType + 1, end) +
+ diagnostic.message.substring(end + 1);
+ } else if (countBinding === 3 && countBindable === 1) {
+ // Only keep Type '...' is not assignable to type '...' in
+ // Type Bindings<...> is not assignable to type Bindable<...>, Type Binding<...> is not assignable to type Bindable<...>, Type '...' is not assignable to type '...'
+ const lines = diagnostic.message.split('\n');
+ if (lines.length === 3) {
+ diagnostic.message = lines[2].trimStart();
+ }
+ }
+
+ return {
+ ...diagnostic,
+ message: diagnostic.message
+ };
+ }
+
return diagnostic;
}
diff --git a/packages/language-server/src/plugins/typescript/features/RenameProvider.ts b/packages/language-server/src/plugins/typescript/features/RenameProvider.ts
index ff1902766..3ba763e3c 100644
--- a/packages/language-server/src/plugins/typescript/features/RenameProvider.ts
+++ b/packages/language-server/src/plugins/typescript/features/RenameProvider.ts
@@ -37,6 +37,9 @@ interface TsRenameLocation extends ts.RenameLocation {
newName?: string;
}
+const bind = 'bind:';
+const bindShortHandGeneratedLength = ':__sveltets_2_binding('.length;
+
export class RenameProviderImpl implements RenameProvider {
constructor(
private readonly lsAndTsDocResolver: LSAndTSDocResolver,
@@ -73,7 +76,7 @@ export class RenameProviderImpl implements RenameProvider {
const renameLocations = lang.findRenameLocations(
tsDoc.filePath,
- offset,
+ offset + (renameInfo.bindShorthand || 0),
false,
false,
true
@@ -157,6 +160,7 @@ export class RenameProviderImpl implements RenameProvider {
):
| (ts.RenameInfoSuccess & {
isStore?: boolean;
+ bindShorthand?: number;
})
| null {
// Don't allow renames in error-state, because then there is no generated svelte2tsx-code
@@ -165,6 +169,15 @@ export class RenameProviderImpl implements RenameProvider {
return null;
}
+ const svelteNode = tsDoc.svelteNodeAt(originalPosition);
+
+ let bindOffset = 0;
+ const bindingShorthand = this.getBindingShorthand(tsDoc, originalPosition, svelteNode);
+ if (bindingShorthand) {
+ bindOffset = bindingShorthand.end - bindingShorthand.start;
+ generatedOffset += bindShortHandGeneratedLength + bindOffset;
+ }
+
const renameInfo = lang.getRenameInfo(tsDoc.filePath, generatedOffset, {
allowRenameOfImportPath: false
});
@@ -178,7 +191,6 @@ export class RenameProviderImpl implements RenameProvider {
return null;
}
- const svelteNode = tsDoc.svelteNodeAt(originalPosition);
if (
isInHTMLTagRange(doc.html, doc.offsetAt(originalPosition)) ||
isAttributeName(svelteNode, 'Element') ||
@@ -188,16 +200,22 @@ export class RenameProviderImpl implements RenameProvider {
}
// If $store is renamed, only allow rename for $|store|
- if (tsDoc.getFullText().charAt(renameInfo.triggerSpan.start) === '$') {
+ const text = tsDoc.getFullText();
+ if (text.charAt(renameInfo.triggerSpan.start) === '$') {
const definition = lang.getDefinitionAndBoundSpan(tsDoc.filePath, generatedOffset)
?.definitions?.[0];
- if (definition && isTextSpanInGeneratedCode(tsDoc.getFullText(), definition.textSpan)) {
+ if (definition && isTextSpanInGeneratedCode(text, definition.textSpan)) {
renameInfo.triggerSpan.start++;
renameInfo.triggerSpan.length--;
(renameInfo as any).isStore = true;
}
}
+ if (bindOffset) {
+ renameInfo.triggerSpan.start -= bindShortHandGeneratedLength + bindOffset;
+ (renameInfo as any).bindShorthand = bindShortHandGeneratedLength + bindOffset;
+ }
+
return renameInfo;
}
@@ -325,7 +343,6 @@ export class RenameProviderImpl implements RenameProvider {
replacementsForProp,
snapshots
);
- const bind = 'bind:';
// Adjust shorthands
return renameLocations.map((location) => {
@@ -351,31 +368,29 @@ export class RenameProviderImpl implements RenameProvider {
const { parent } = snapshot;
- let rangeStart = parent.offsetAt(location.range.start);
- let suffixText = location.suffixText?.trimStart();
-
- // suffix is of the form `: oldVarName` -> hints at a shorthand
- if (!suffixText?.startsWith(':') || !getNodeIfIsInStartTag(parent.html, rangeStart)) {
- return location;
- }
-
- const original = parent.getText({
- start: Position.create(
- location.range.start.line,
- location.range.start.character - bind.length
- ),
- end: location.range.end
- });
-
- if (original.startsWith(bind)) {
+ const bindingShorthand = this.getBindingShorthand(snapshot, location.range.start);
+ if (bindingShorthand) {
// bind:|foo| -> bind:|newName|={foo}
+ const name = parent
+ .getText()
+ .substring(bindingShorthand.start, bindingShorthand.end);
return {
...location,
prefixText: '',
- suffixText: `={${original.slice(bind.length)}}`
+ suffixText: `={${name}}`
};
}
+ let rangeStart = parent.offsetAt(location.range.start);
+
+ // suffix is of the form `: oldVarName` -> hints at a shorthand
+ if (
+ !location.suffixText?.trimStart()?.startsWith(':') ||
+ !getNodeIfIsInStartTag(parent.html, rangeStart)
+ ) {
+ return location;
+ }
+
if (snapshot.getOriginalText().charAt(rangeStart - 1) === '{') {
// {|foo|} -> |{foo|}
rangeStart--;
@@ -582,8 +597,6 @@ export class RenameProviderImpl implements RenameProvider {
renameLocations: TsRenameLocation[],
snapshots: SnapshotMap
): TsRenameLocation[] {
- const bind = 'bind:';
-
return renameLocations.map((location) => {
const sourceFile = lang.getProgram()?.getSourceFile(location.fileName);
@@ -625,6 +638,38 @@ export class RenameProviderImpl implements RenameProvider {
suffixText: '}'
};
}
+
+ if (snapshot.isSvelte5Plus) {
+ const bindingShorthand = this.getBindingShorthand(
+ snapshot,
+ location.range.start
+ );
+ if (bindingShorthand) {
+ const name = parent
+ .getText()
+ .substring(bindingShorthand.start, bindingShorthand.end);
+ const start = {
+ line: location.range.start.line,
+ character: location.range.start.character - name.length
+ };
+ // If binding is followed by the closing tag, start is one character too soon,
+ // else binding is ending one character too far
+ if (parent.getText().charAt(parent.offsetAt(start)) === ':') {
+ start.character++;
+ } else {
+ location.range.end.character--;
+ }
+ return {
+ ...location,
+ range: {
+ start: start,
+ end: location.range.end
+ },
+ prefixText: name + '={',
+ suffixText: '}'
+ };
+ }
+ }
}
if (!prefixText || prefixText.slice(-1) !== ':') {
@@ -668,4 +713,17 @@ export class RenameProviderImpl implements RenameProvider {
return location;
});
}
+
+ private getBindingShorthand(
+ snapshot: SvelteDocumentSnapshot,
+ position: Position,
+ svelteNode = snapshot.svelteNodeAt(position)
+ ) {
+ if (
+ svelteNode?.parent?.type === 'Binding' &&
+ svelteNode.parent.expression.end === svelteNode.parent.end
+ ) {
+ return svelteNode.parent.expression;
+ }
+ }
}
diff --git a/packages/language-server/src/plugins/typescript/svelte-ast-utils.ts b/packages/language-server/src/plugins/typescript/svelte-ast-utils.ts
index df51edb26..b023a23c3 100644
--- a/packages/language-server/src/plugins/typescript/svelte-ast-utils.ts
+++ b/packages/language-server/src/plugins/typescript/svelte-ast-utils.ts
@@ -8,6 +8,7 @@ export interface SvelteNode {
end: number;
type: string;
parent?: SvelteNode;
+ [key: string]: any;
}
type HTMLLike = 'Element' | 'InlineComponent' | 'Body' | 'Window';
diff --git a/packages/language-server/src/utils.ts b/packages/language-server/src/utils.ts
index 34d828937..a79c49999 100644
--- a/packages/language-server/src/utils.ts
+++ b/packages/language-server/src/utils.ts
@@ -341,3 +341,45 @@ export function removeLineWithString(str: string, keyword: string) {
const filteredLines = lines.filter((line) => !line.includes(keyword));
return filteredLines.join('\n');
}
+
+/**
+ * Traverses a string and returns the index of the end character, taking into account quotes, curlies and generic tags.
+ */
+export function traverseTypeString(str: string, start: number, endChar: string): number {
+ let singleQuoteOpen = false;
+ let doubleQuoteOpen = false;
+ let countCurlyBrace = 0;
+ let countAngleBracket = 0;
+
+ for (let i = start; i < str.length; i++) {
+ const char = str[i];
+
+ if (!doubleQuoteOpen && char === "'") {
+ singleQuoteOpen = !singleQuoteOpen;
+ } else if (!singleQuoteOpen && char === '"') {
+ doubleQuoteOpen = !doubleQuoteOpen;
+ } else if (!doubleQuoteOpen && !singleQuoteOpen) {
+ if (char === '{') {
+ countCurlyBrace++;
+ } else if (char === '}') {
+ countCurlyBrace--;
+ } else if (char === '<') {
+ countAngleBracket++;
+ } else if (char === '>') {
+ countAngleBracket--;
+ }
+ }
+
+ if (
+ !singleQuoteOpen &&
+ !doubleQuoteOpen &&
+ countCurlyBrace === 0 &&
+ countAngleBracket === 0 &&
+ char === endChar
+ ) {
+ return i;
+ }
+ }
+
+ return -1;
+}
diff --git a/packages/language-server/test/plugins/svelte/SveltePlugin.test.ts b/packages/language-server/test/plugins/svelte/SveltePlugin.test.ts
index db5d5e7d4..2712a095c 100644
--- a/packages/language-server/test/plugins/svelte/SveltePlugin.test.ts
+++ b/packages/language-server/test/plugins/svelte/SveltePlugin.test.ts
@@ -12,6 +12,9 @@ import * as importPackage from '../../../src/importPackage';
import sinon from 'sinon';
import { join } from 'path';
import { pathToUrl, urlToPath } from '../../../src/utils';
+import { VERSION } from 'svelte/compiler';
+
+const isSvelte5Plus = Number(VERSION.split('.')[0]) >= 5;
describe('Svelte Plugin', () => {
function setup(
@@ -35,9 +38,11 @@ describe('Svelte Plugin', () => {
const diagnostics = await plugin.getDiagnostics(document);
const diagnostic = Diagnostic.create(
Range.create(1, 0, 1, 21),
- 'A11y: element should have an alt attribute',
+ isSvelte5Plus
+ ? ' element should have an alt attribute'
+ : 'A11y: element should have an alt attribute',
DiagnosticSeverity.Warning,
- 'a11y-missing-attribute',
+ isSvelte5Plus ? 'a11y_missing_attribute' : 'a11y-missing-attribute',
'svelte'
);
@@ -50,9 +55,9 @@ describe('Svelte Plugin', () => {
const diagnostics = await plugin.getDiagnostics(document);
const diagnostic = Diagnostic.create(
Range.create(0, 10, 0, 18),
- 'whatever is not declared',
+ isSvelte5Plus ? 'Can only bind to state or props' : 'whatever is not declared',
DiagnosticSeverity.Error,
- 'binding-undeclared',
+ isSvelte5Plus ? 'invalid_binding_value' : 'binding-undeclared',
'svelte'
);
diff --git a/packages/language-server/test/plugins/svelte/features/getDiagnostics.test.ts b/packages/language-server/test/plugins/svelte/features/getDiagnostics.test.ts
index 8ce588264..9f7ef475b 100644
--- a/packages/language-server/test/plugins/svelte/features/getDiagnostics.test.ts
+++ b/packages/language-server/test/plugins/svelte/features/getDiagnostics.test.ts
@@ -12,6 +12,9 @@ import { SvelteConfig } from '../../../../src/lib/documents/configLoader';
import { CompilerWarningsSettings, LSConfigManager } from '../../../../src/ls-config';
import { pathToUrl } from '../../../../src/utils';
import { SveltePlugin } from '../../../../src/plugins';
+import { VERSION } from 'svelte/compiler';
+
+const isSvelte5Plus = Number(VERSION.split('.')[0]) >= 5;
describe('SveltePlugin#getDiagnostics', () => {
async function expectDiagnosticsFor({
@@ -286,16 +289,14 @@ describe('SveltePlugin#getDiagnostics', () => {
}),
getCompiled: () =>
Promise.resolve({
- stats: {
- warnings: [
- {
- start: { line: 1, column: 0 },
- end: { line: 1, column: 0 },
- message: 'warning',
- code: 123
- }
- ]
- }
+ warnings: [
+ {
+ start: { line: 1, column: 0 },
+ end: { line: 1, column: 0 },
+ message: 'warning',
+ code: 123
+ }
+ ]
}),
config: {}
})
@@ -415,16 +416,14 @@ describe('SveltePlugin#getDiagnostics', () => {
}),
getCompiled: () =>
Promise.resolve({
- stats: {
- warnings: [
- {
- start: { line: 1, column: 0 },
- end: { line: 1, column: 0 },
- message: 'warning',
- code: '123'
- }
- ]
- }
+ warnings: [
+ {
+ start: { line: 1, column: 0 },
+ end: { line: 1, column: 0 },
+ message: 'warning',
+ code: '123'
+ }
+ ]
}),
config: {},
settings: { 123: 'error' }
@@ -460,7 +459,7 @@ describe('SveltePlugin#getDiagnostics', () => {
"Component has unused export property 'name'. If it is for external reference only, please consider using `export const name`",
severity: 2,
source: 'svelte',
- code: 'unused-export-let'
+ code: isSvelte5Plus ? 'unused_export_let' : 'unused-export-let'
}
]);
});
@@ -472,10 +471,14 @@ describe('SveltePlugin#getDiagnostics', () => {
assert.deepStrictEqual(diagnostics, [
{
range: { start: { line: 1, character: 4 }, end: { line: 1, character: 26 } },
- message: '$: has no effect in a module script',
+ message: isSvelte5Plus
+ ? 'Reactive declarations only exist at the top level of the instance script'
+ : '$: has no effect in a module script',
severity: 2,
source: 'svelte',
- code: 'module-script-reactive-declaration'
+ code: isSvelte5Plus
+ ? 'no_reactive_declaration'
+ : 'module-script-reactive-declaration'
}
]);
});
@@ -486,7 +489,7 @@ describe('SveltePlugin#getDiagnostics', () => {
assert.deepStrictEqual(diagnostics, [
{
- code: 'unused-export-let',
+ code: isSvelte5Plus ? 'unused_export_let' : 'unused-export-let',
message:
"Component has unused export property 'unused1'. If it is for external reference only, please consider using `export const unused1`",
range: {
@@ -496,14 +499,14 @@ describe('SveltePlugin#getDiagnostics', () => {
},
end: {
line: 5,
- character: 27
+ character: isSvelte5Plus ? 20 : 27
}
},
severity: 2,
source: 'svelte'
},
{
- code: 'unused-export-let',
+ code: isSvelte5Plus ? 'unused_export_let' : 'unused-export-let',
message:
"Component has unused export property 'unused2'. If it is for external reference only, please consider using `export const unused2`",
range: {
@@ -513,7 +516,7 @@ describe('SveltePlugin#getDiagnostics', () => {
},
end: {
line: 6,
- character: 27
+ character: isSvelte5Plus ? 20 : 27
}
},
severity: 2,
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/$$events/expected_svelte_5.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/$$events/expected_svelte_5.json
new file mode 100644
index 000000000..782e41e55
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/$$events/expected_svelte_5.json
@@ -0,0 +1,58 @@
+[
+ {
+ "code": 6385,
+ "message": "'createEventDispatcher' is deprecated.",
+ "range": {
+ "end": {
+ "character": 34,
+ "line": 1
+ },
+ "start": {
+ "character": 13,
+ "line": 1
+ }
+ },
+ "severity": 4,
+ "source": "ts",
+ "tags": [2]
+ },
+ {
+ "code": 6387,
+ "message": "The signature '(): EventDispatcher<__sveltets_2_CustomEvents<$$Events>>' of 'createEventDispatcher' is deprecated.",
+ "range": {
+ "end": {
+ "character": 42,
+ "line": 8
+ },
+ "start": {
+ "character": 21,
+ "line": 8
+ }
+ },
+ "severity": 4,
+ "source": "ts",
+ "tags": [2]
+ },
+ {
+ "range": {
+ "start": { "line": 12, "character": 20 },
+ "end": { "line": 12, "character": 24 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Argument of type 'boolean' is not assignable to parameter of type 'string'.",
+ "code": 2345,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 13, "character": 13 },
+ "end": { "line": 13, "character": 20 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Argument of type '\"click\"' is not assignable to parameter of type '\"foo\"'.",
+ "code": 2345,
+ "tags": []
+ }
+]
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/$$props-usage/expected_svelte_5.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/$$props-usage/expected_svelte_5.json
new file mode 100644
index 000000000..f98179a38
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/$$props-usage/expected_svelte_5.json
@@ -0,0 +1,32 @@
+[
+ {
+ "range": {
+ "start": { "line": 10, "character": 7 },
+ "end": { "line": 10, "character": 16 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 11, "character": 43 },
+ "end": { "line": 11, "character": 54 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Object literal may only specify known properties, and '\"invalidProp\"' does not exist in type 'WithBindings<{ exported1: string; exported2?: string | undefined; exported3: string; }>'.",
+ "code": 2353,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 12, "character": 1 }, "end": { "line": 12, "character": 6 } },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type '{}' is missing the following properties from type 'WithBindings<{ exported1: string; exported2?: string | undefined; exported3: string; }>': exported1, exported3",
+ "code": 2739,
+ "tags": []
+ }
+]
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/$store-bind/expected_svelte_5.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/$store-bind/expected_svelte_5.json
new file mode 100644
index 000000000..9c6757bf6
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/$store-bind/expected_svelte_5.json
@@ -0,0 +1,46 @@
+[
+ {
+ "range": {
+ "start": { "line": 17, "character": 24 },
+ "end": { "line": 17, "character": 34 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'number' is not assignable to type 'boolean'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 18, "character": 16 },
+ "end": { "line": 18, "character": 20 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'boolean' is not assignable to type 'number'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 19, "character": 24 },
+ "end": { "line": 19, "character": 41 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'number' is not assignable to type 'boolean'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 20, "character": 16 },
+ "end": { "line": 20, "character": 20 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'Binding' is not assignable to type 'Bindable'.",
+ "code": 2322,
+ "tags": []
+ }
+]
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bind-this/expected_svelte_5.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bind-this/expected_svelte_5.json
new file mode 100644
index 000000000..09171f654
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bind-this/expected_svelte_5.json
@@ -0,0 +1,98 @@
+[
+ {
+ "range": { "start": { "line": 9, "character": 6 }, "end": { "line": 9, "character": 13 } },
+ "severity": 4,
+ "source": "ts",
+ "message": "'element' is declared but its value is never read.",
+ "code": 6133,
+ "tags": [1]
+ },
+ {
+ "range": {
+ "start": { "line": 18, "character": 2 },
+ "end": { "line": 18, "character": 11 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Variable 'component' is used before being assigned.",
+ "code": 2454,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 40, "character": 16 },
+ "end": { "line": 40, "character": 23 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'HTMLDivElement' is missing the following properties from type 'HTMLInputElement': accept, alt, autocomplete, capture, and 54 more.",
+ "code": 2740,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 41, "character": 34 },
+ "end": { "line": 41, "character": 48 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'Component' is not assignable to type 'OtherComponent'.\n The types of '$$prop_def.prop' are incompatible between these types.\n Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 42, "character": 35 },
+ "end": { "line": 42, "character": 57 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'ComponentWithFunction1' is not assignable to type 'ComponentWithFunction2'.\n Types of property 'action' are incompatible.\n Type '(a: number) => string | number' is not assignable to type '() => string'.\n Target signature provides too few arguments. Expected 1 or more, but got 0.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 43, "character": 1 },
+ "end": { "line": 43, "character": 17 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type '{}' is not assignable to type 'PropsWithChildren<{ prop: boolean; }, any> | undefined'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 43, "character": 46 },
+ "end": { "line": 43, "character": 60 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'Component' is not assignable to type 'OtherComponent'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 46, "character": 45 },
+ "end": { "line": 46, "character": 65 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'ComponentWithGeneric' is not assignable to type 'ComponentWithGeneric'.\n Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 47, "character": 1 },
+ "end": { "line": 47, "character": 17 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type '{}' is not assignable to type 'PropsWithChildren<{ prop: boolean; }, any> | undefined'.",
+ "code": 2322,
+ "tags": []
+ }
+]
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/Legacy.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/Legacy.svelte
new file mode 100644
index 000000000..1bd159644
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/Legacy.svelte
@@ -0,0 +1,6 @@
+
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/Runes.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/Runes.svelte
new file mode 100644
index 000000000..34b9e88d7
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/Runes.svelte
@@ -0,0 +1,7 @@
+
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/expected_svelte_5.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/expected_svelte_5.json
new file mode 100644
index 000000000..abd096989
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/expected_svelte_5.json
@@ -0,0 +1,53 @@
+[
+ {
+ "code": 2322,
+ "message": "Type 'Binding' is not assignable to type 'string'.",
+ "range": {
+ "end": {
+ "character": 20,
+ "line": 25
+ },
+ "start": {
+ "character": 12,
+ "line": 25
+ }
+ },
+ "severity": 1,
+ "source": "ts",
+ "tags": []
+ },
+ {
+ "code": 2353,
+ "message": "Object literal may only specify known properties, and 'only_bind' does not exist in type '{ readonly?: string | undefined; can_bind?: Bindable; }'.",
+ "range": {
+ "end": {
+ "character": 21,
+ "line": 26
+ },
+ "start": {
+ "character": 12,
+ "line": 26
+ }
+ },
+ "severity": 1,
+ "source": "ts",
+ "tags": []
+ },
+ {
+ "code": 2353,
+ "message": "Object literal may only specify known properties, and 'only_bind' does not exist in type '{ readonly?: string | undefined; can_bind?: Bindable; }'.",
+ "range": {
+ "end": {
+ "character": 17,
+ "line": 27
+ },
+ "start": {
+ "character": 8,
+ "line": 27
+ }
+ },
+ "severity": 1,
+ "source": "ts",
+ "tags": []
+ }
+]
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/expectedv2.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/expectedv2.json
new file mode 100644
index 000000000..fe51488c7
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/expectedv2.json
@@ -0,0 +1 @@
+[]
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/input.svelte b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/input.svelte
new file mode 100644
index 000000000..1dc072434
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/bindings/input.svelte
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/checkjs-nostrict/component-props-js/expected_svelte_5.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/checkjs-nostrict/component-props-js/expected_svelte_5.json
new file mode 100644
index 000000000..b17cb454d
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/checkjs-nostrict/component-props-js/expected_svelte_5.json
@@ -0,0 +1,83 @@
+[
+ {
+ "range": { "start": { "line": 6, "character": 1 }, "end": { "line": 6, "character": 9 } },
+ "severity": 1,
+ "source": "js",
+ "message": "Property 'required' is missing in type '{}' but required in type 'WithBindings<{ required: string; optional1?: string; optional2?: string; }>'.",
+ "code": 2741,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 8, "character": 57 }, "end": { "line": 8, "character": 68 } },
+ "severity": 1,
+ "source": "js",
+ "message": "Object literal may only specify known properties, and '\"doesntExist\"' does not exist in type 'WithBindings<{ required: string; optional1?: string; optional2?: string; }>'.",
+ "code": 2353,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 9, "character": 10 }, "end": { "line": 9, "character": 18 } },
+ "severity": 1,
+ "source": "js",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 9, "character": 26 }, "end": { "line": 9, "character": 35 } },
+ "severity": 1,
+ "source": "js",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 9, "character": 43 }, "end": { "line": 9, "character": 52 } },
+ "severity": 1,
+ "source": "js",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 10, "character": 1 }, "end": { "line": 10, "character": 9 } },
+ "severity": 1,
+ "source": "js",
+ "message": "Property 'required' is missing in type '{}' but required in type 'WithBindings<{ required: string; optional1?: string; optional2?: string; }>'.",
+ "code": 2741,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 12, "character": 10 },
+ "end": { "line": 12, "character": 18 }
+ },
+ "severity": 1,
+ "source": "js",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 12, "character": 26 },
+ "end": { "line": 12, "character": 35 }
+ },
+ "severity": 1,
+ "source": "js",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 12, "character": 43 },
+ "end": { "line": 12, "character": 52 }
+ },
+ "severity": 1,
+ "source": "js",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ }
+]
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/checkjs-nostrict/component-props-ts/expected_svelte_5.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/checkjs-nostrict/component-props-ts/expected_svelte_5.json
new file mode 100644
index 000000000..1468ca1c4
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/checkjs-nostrict/component-props-ts/expected_svelte_5.json
@@ -0,0 +1,83 @@
+[
+ {
+ "range": { "start": { "line": 6, "character": 1 }, "end": { "line": 6, "character": 9 } },
+ "severity": 1,
+ "source": "ts",
+ "message": "Property 'required' is missing in type '{}' but required in type 'WithBindings<{ required: string; optional1?: string; optional2?: string; }>'.",
+ "code": 2741,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 8, "character": 57 }, "end": { "line": 8, "character": 68 } },
+ "severity": 1,
+ "source": "ts",
+ "message": "Object literal may only specify known properties, and '\"doesntExist\"' does not exist in type 'WithBindings<{ required: string; optional1?: string; optional2?: string; }>'.",
+ "code": 2353,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 9, "character": 10 }, "end": { "line": 9, "character": 18 } },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 9, "character": 26 }, "end": { "line": 9, "character": 35 } },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 9, "character": 43 }, "end": { "line": 9, "character": 52 } },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 10, "character": 1 }, "end": { "line": 10, "character": 9 } },
+ "severity": 1,
+ "source": "ts",
+ "message": "Property 'required' is missing in type '{}' but required in type 'WithBindings<{ required: string; optional1?: string; optional2?: string; }>'.",
+ "code": 2741,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 12, "character": 10 },
+ "end": { "line": 12, "character": 18 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 12, "character": 26 },
+ "end": { "line": 12, "character": 35 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 12, "character": 43 },
+ "end": { "line": 12, "character": 52 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ }
+]
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/checkjs/component-props-js/expected_svelte_5.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/checkjs/component-props-js/expected_svelte_5.json
new file mode 100644
index 000000000..89c2f2631
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/checkjs/component-props-js/expected_svelte_5.json
@@ -0,0 +1,102 @@
+[
+ {
+ "range": { "start": { "line": 6, "character": 1 }, "end": { "line": 6, "character": 9 } },
+ "severity": 1,
+ "source": "js",
+ "message": "Property 'required' is missing in type '{}' but required in type 'WithBindings<{ required: string; optional1?: string | undefined; optional2?: string | undefined; }>'.",
+ "code": 2741,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 7, "character": 10 }, "end": { "line": 7, "character": 18 } },
+ "severity": 1,
+ "source": "js",
+ "message": "Type 'undefined' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 8, "character": 57 }, "end": { "line": 8, "character": 68 } },
+ "severity": 1,
+ "source": "js",
+ "message": "Object literal may only specify known properties, and '\"doesntExist\"' does not exist in type 'WithBindings<{ required: string; optional1?: string | undefined; optional2?: string | undefined; }>'.",
+ "code": 2353,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 9, "character": 10 }, "end": { "line": 9, "character": 18 } },
+ "severity": 1,
+ "source": "js",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 9, "character": 26 }, "end": { "line": 9, "character": 35 } },
+ "severity": 1,
+ "source": "js",
+ "message": "Type 'true' is not assignable to type 'string | undefined'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 9, "character": 43 }, "end": { "line": 9, "character": 52 } },
+ "severity": 1,
+ "source": "js",
+ "message": "Type 'true' is not assignable to type 'string | undefined'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 10, "character": 1 }, "end": { "line": 10, "character": 9 } },
+ "severity": 1,
+ "source": "js",
+ "message": "Property 'required' is missing in type '{}' but required in type 'WithBindings<{ required: string; optional1?: string | undefined; optional2?: string | undefined; }>'.",
+ "code": 2741,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 11, "character": 10 },
+ "end": { "line": 11, "character": 18 }
+ },
+ "severity": 1,
+ "source": "js",
+ "message": "Type 'undefined' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 12, "character": 10 },
+ "end": { "line": 12, "character": 18 }
+ },
+ "severity": 1,
+ "source": "js",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 12, "character": 26 },
+ "end": { "line": 12, "character": 35 }
+ },
+ "severity": 1,
+ "source": "js",
+ "message": "Type 'true' is not assignable to type 'string | undefined'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 12, "character": 43 },
+ "end": { "line": 12, "character": 52 }
+ },
+ "severity": 1,
+ "source": "js",
+ "message": "Type 'true' is not assignable to type 'string | undefined'.",
+ "code": 2322,
+ "tags": []
+ }
+]
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/checkjs/component-props-ts/expected_svelte_5.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/checkjs/component-props-ts/expected_svelte_5.json
new file mode 100644
index 000000000..097f3edf7
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/checkjs/component-props-ts/expected_svelte_5.json
@@ -0,0 +1,102 @@
+[
+ {
+ "range": { "start": { "line": 6, "character": 1 }, "end": { "line": 6, "character": 9 } },
+ "severity": 1,
+ "source": "ts",
+ "message": "Property 'required' is missing in type '{}' but required in type 'WithBindings<{ required: string; optional1?: string | undefined; optional2?: string | undefined; }>'.",
+ "code": 2741,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 7, "character": 10 }, "end": { "line": 7, "character": 18 } },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'undefined' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 8, "character": 57 }, "end": { "line": 8, "character": 68 } },
+ "severity": 1,
+ "source": "ts",
+ "message": "Object literal may only specify known properties, and '\"doesntExist\"' does not exist in type 'WithBindings<{ required: string; optional1?: string | undefined; optional2?: string | undefined; }>'.",
+ "code": 2353,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 9, "character": 10 }, "end": { "line": 9, "character": 18 } },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 9, "character": 26 }, "end": { "line": 9, "character": 35 } },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'true' is not assignable to type 'string | undefined'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 9, "character": 43 }, "end": { "line": 9, "character": 52 } },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'true' is not assignable to type 'string | undefined'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 10, "character": 1 }, "end": { "line": 10, "character": 9 } },
+ "severity": 1,
+ "source": "ts",
+ "message": "Property 'required' is missing in type '{}' but required in type 'WithBindings<{ required: string; optional1?: string | undefined; optional2?: string | undefined; }>'.",
+ "code": 2741,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 11, "character": 10 },
+ "end": { "line": 11, "character": 18 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'undefined' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 12, "character": 10 },
+ "end": { "line": 12, "character": 18 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 12, "character": 26 },
+ "end": { "line": 12, "character": 35 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'true' is not assignable to type 'string | undefined'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 12, "character": 43 },
+ "end": { "line": 12, "character": 52 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'true' is not assignable to type 'string | undefined'.",
+ "code": 2322,
+ "tags": []
+ }
+]
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/component-invalid/expected_svelte_5.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/component-invalid/expected_svelte_5.json
new file mode 100644
index 000000000..81e4cc4cd
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/component-invalid/expected_svelte_5.json
@@ -0,0 +1,57 @@
+[
+ {
+ "range": {
+ "start": { "line": 19, "character": 1 },
+ "end": { "line": 19, "character": 11 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Argument of type 'typeof DoesntWork' is not assignable to parameter of type 'ConstructorOfATypedSvelteComponent'.\n Type 'DoesntWork' is missing the following properties from type 'ATypedSvelteComponent': $$prop_def, $$events_def, $$slot_def, $on\n\nPossible causes:\n- You use the instance type of a component where you should use the constructor type\n- Type definitions are missing for this Svelte Component. If you are using Svelte 3.31+, use SvelteComponentTyped to add a definition:\n import type { SvelteComponentTyped } from \"svelte\";\n class ComponentName extends SvelteComponentTyped<{propertyName: string;}> {}",
+ "code": 2345,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 20, "character": 10 },
+ "end": { "line": 20, "character": 25 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'boolean' is not assignable to type 'Binding'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 21, "character": 24 },
+ "end": { "line": 21, "character": 34 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Argument of type 'typeof DoesntWork' is not assignable to parameter of type 'ConstructorOfATypedSvelteComponent'.\n\nPossible causes:\n- You use the instance type of a component where you should use the constructor type\n- Type definitions are missing for this Svelte Component. If you are using Svelte 3.31+, use SvelteComponentTyped to add a definition:\n import type { SvelteComponentTyped } from \"svelte\";\n class ComponentName extends SvelteComponentTyped<{propertyName: string;}> {}",
+ "code": 2345,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 24, "character": 1 },
+ "end": { "line": 24, "character": 11 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Argument of type 'typeof DoesntWork' is not assignable to parameter of type 'ConstructorOfATypedSvelteComponent'.\n\nPossible causes:\n- You use the instance type of a component where you should use the constructor type\n- Type definitions are missing for this Svelte Component. If you are using Svelte 3.31+, use SvelteComponentTyped to add a definition:\n import type { SvelteComponentTyped } from \"svelte\";\n class ComponentName extends SvelteComponentTyped<{propertyName: string;}> {}",
+ "code": 2345,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 27, "character": 24 },
+ "end": { "line": 27, "character": 34 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Argument of type 'typeof DoesntWork' is not assignable to parameter of type 'ConstructorOfATypedSvelteComponent'.\n\nPossible causes:\n- You use the instance type of a component where you should use the constructor type\n- Type definitions are missing for this Svelte Component. If you are using Svelte 3.31+, use SvelteComponentTyped to add a definition:\n import type { SvelteComponentTyped } from \"svelte\";\n class ComponentName extends SvelteComponentTyped<{propertyName: string;}> {}",
+ "code": 2345,
+ "tags": []
+ }
+]
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/expected_svelte_5.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/expected_svelte_5.json
new file mode 100644
index 000000000..ae37bf13f
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/custom-types/expected_svelte_5.json
@@ -0,0 +1,103 @@
+[
+ {
+ "range": { "start": { "line": 4, "character": 26 }, "end": { "line": 4, "character": 27 } },
+ "severity": 4,
+ "source": "ts",
+ "message": "Parameter 'e' implicitly has an 'any' type, but a better type may be inferred from usage.",
+ "code": 7044,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 22, "character": 26 },
+ "end": { "line": 22, "character": 27 }
+ },
+ "severity": 4,
+ "source": "ts",
+ "message": "Parameter 'e' implicitly has an 'any' type, but a better type may be inferred from usage.",
+ "code": 7044,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 3, "character": 5 }, "end": { "line": 3, "character": 19 } },
+ "severity": 1,
+ "source": "ts",
+ "message": "Object literal may only specify known properties, and '\"owntypefromold\"' does not exist in type 'HTMLProps<\"div\", HTMLAttributes>'.",
+ "code": 2353,
+ "tags": []
+ },
+ {
+ "range": { "start": { "line": 4, "character": 8 }, "end": { "line": 4, "character": 23 } },
+ "severity": 1,
+ "source": "ts",
+ "message": "Object literal may only specify known properties, and '\"on:ownclickfromold\"' does not exist in type 'HTMLProps<\"div\", HTMLAttributes>'.",
+ "code": 2353,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 15, "character": 13 },
+ "end": { "line": 15, "character": 22 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 16, "character": 13 },
+ "end": { "line": 16, "character": 23 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Object literal may only specify known properties, and '\"doesnexist\"' does not exist in type '{ attribute?: string; }'.",
+ "code": 2353,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 19, "character": 5 },
+ "end": { "line": 19, "character": 12 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Type 'boolean' is not assignable to type 'string'.",
+ "code": 2322,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 20, "character": 5 },
+ "end": { "line": 20, "character": 19 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Object literal may only specify known properties, and '\"owntypefromold\"' does not exist in type 'HTMLProps<\"div\", HTMLAttributes>'.",
+ "code": 2353,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 21, "character": 34 },
+ "end": { "line": 21, "character": 39 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Property 'wrong' does not exist on type '{ foo: string; }'.",
+ "code": 2339,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": { "line": 22, "character": 8 },
+ "end": { "line": 22, "character": 23 }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Object literal may only specify known properties, and '\"on:ownclickfromold\"' does not exist in type 'HTMLProps<\"div\", HTMLAttributes>'.",
+ "code": 2353,
+ "tags": []
+ }
+]
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/each/expected_svelte_5.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/each/expected_svelte_5.json
new file mode 100644
index 000000000..6c90ac01b
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/each/expected_svelte_5.json
@@ -0,0 +1,36 @@
+[
+ {
+ "range": {
+ "start": {
+ "line": 29,
+ "character": 7
+ },
+ "end": {
+ "line": 29,
+ "character": 24
+ }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Argument of type '{}' is not assignable to parameter of type 'ArrayLike | Iterable'.",
+ "code": 2345,
+ "tags": []
+ },
+ {
+ "range": {
+ "start": {
+ "line": 33,
+ "character": 7
+ },
+ "end": {
+ "line": 33,
+ "character": 24
+ }
+ },
+ "severity": 1,
+ "source": "ts",
+ "message": "Argument of type 'number' is not assignable to parameter of type 'ArrayLike | Iterable'.",
+ "code": 2345,
+ "tags": []
+ }
+]
diff --git a/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/parser-error/expected_svelte_5.json b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/parser-error/expected_svelte_5.json
new file mode 100644
index 000000000..c0fcc5b6d
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/features/diagnostics/fixtures/parser-error/expected_svelte_5.json
@@ -0,0 +1,9 @@
+[
+ {
+ "range": { "start": { "line": 1, "character": 0 }, "end": { "line": 1, "character": 0 } },
+ "severity": 1,
+ "source": "js",
+ "message": "A component can have a single top-level `