From 027ab23e3e59939ad1f018a34ca5e0386cbaf829 Mon Sep 17 00:00:00 2001 From: Simon H <5968653+dummdidumm@users.noreply.github.com> Date: Tue, 2 Jul 2024 17:53:21 +0200 Subject: [PATCH] chore: better "cannot use `bind:`" error message (#2429) --- .../features/DiagnosticsProvider.ts | 29 +++++++++++++------ .../fixtures/bindings/expected_svelte_5.json | 4 +-- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/packages/language-server/src/plugins/typescript/features/DiagnosticsProvider.ts b/packages/language-server/src/plugins/typescript/features/DiagnosticsProvider.ts index 97ed3a9b6..e68f0d826 100644 --- a/packages/language-server/src/plugins/typescript/features/DiagnosticsProvider.ts +++ b/packages/language-server/src/plugins/typescript/features/DiagnosticsProvider.ts @@ -21,14 +21,7 @@ import { isStoreVariableIn$storeDeclaration, get$storeOffsetOf$storeDeclaration } from './utils'; -import { - not, - flatten, - passMap, - swapRangeStartEndIfNecessary, - memoize, - traverseTypeString -} from '../../../utils'; +import { not, flatten, passMap, swapRangeStartEndIfNecessary, memoize } from '../../../utils'; import { LSConfigManager } from '../../../ls-config'; import { isAttributeName, isEventHandler } from '../svelte-ast-utils'; @@ -206,7 +199,25 @@ function moveBindingErrorMessage( (attr: any) => attr.type === 'Binding' && attr.name === name ); if (binding) { - diagnostic.message = 'Cannot bind: to this property\n\n' + diagnostic.message; + // try to make the error more readable for english users + if ( + diagnostic.message.startsWith("Type '") && + diagnostic.message.includes("is not assignable to type '") + ) { + const idx = diagnostic.message.indexOf(`Type '"`) + `Type '"`.length; + const propName = diagnostic.message.substring( + idx, + diagnostic.message.indexOf('"', idx) + ); + diagnostic.message = + "Cannot use 'bind:' with this property. It is declared as non-bindable inside the component.\n" + + `To mark a property as bindable: 'let { ${propName} = $bindable() = $props()'`; + } else { + diagnostic.message = + "Cannot use 'bind:' with this property. It is declared as non-bindable inside the component.\n" + + `To mark a property as bindable: 'let { prop = $bindable() = $props()'\n\n` + + diagnostic.message; + } diagnostic.range = { start: document.positionAt(binding.start), end: document.positionAt(binding.end) 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 index 2bc241532..66d3fc759 100644 --- 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 @@ -1,7 +1,7 @@ [ { "code": 2322, - "message": "Cannot bind: to this property\n\nType '\"readonly\"' is not assignable to type '\"can_bind\"'.", + "message": "Cannot use 'bind:' with this property. It is declared as non-bindable inside the component.\nTo mark a property as bindable: 'let { readonly = $bindable() = $props()'", "range": { "end": { "character": 20, @@ -35,7 +35,7 @@ }, { "code": 2322, - "message": "Cannot bind: to this property\n\nType '\"only_bind\"' is not assignable to type '\"can_bind\"'.", + "message": "Cannot use 'bind:' with this property. It is declared as non-bindable inside the component.\nTo mark a property as bindable: 'let { only_bind = $bindable() = $props()'", "range": { "end": { "character": 21,