From 1a5fb8fd51cdec1a72df9ec3100317bea83698aa Mon Sep 17 00:00:00 2001
From: Robert Gieseke <rob.g@web.de>
Date: Fri, 21 Mar 2025 14:28:44 +0100
Subject: [PATCH] fix: Keep inlined JSDoc comments in property conversion of
 svelte-migrate (#15567)

* Add failing JSDoc property svelte-migrate conversion tests

* Add further test case and remove default value in JSDoc output

* Look for inlined JSDoc comments after a hyphen

* Add changeset
---
 .changeset/happy-cameras-bow.md                    |  5 +++++
 packages/svelte/src/compiler/migrate/index.js      |  7 +++++--
 .../samples/jsdoc-with-comments/input.svelte       |  9 +++++++++
 .../samples/jsdoc-with-comments/output.svelte      | 14 +++++++++++++-
 4 files changed, 32 insertions(+), 3 deletions(-)
 create mode 100644 .changeset/happy-cameras-bow.md

diff --git a/.changeset/happy-cameras-bow.md b/.changeset/happy-cameras-bow.md
new file mode 100644
index 0000000000..47188f4f6d
--- /dev/null
+++ b/.changeset/happy-cameras-bow.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+Keep inlined trailing JSDoc comments of properties when running svelte-migrate
diff --git a/packages/svelte/src/compiler/migrate/index.js b/packages/svelte/src/compiler/migrate/index.js
index 1bb7a69a20..02bb5b1443 100644
--- a/packages/svelte/src/compiler/migrate/index.js
+++ b/packages/svelte/src/compiler/migrate/index.js
@@ -1592,7 +1592,6 @@ function extract_type_and_comment(declarator, state, path) {
 	const comment_start = /** @type {any} */ (comment_node)?.start;
 	const comment_end = /** @type {any} */ (comment_node)?.end;
 	let comment = comment_node && str.original.substring(comment_start, comment_end);
-
 	if (comment_node) {
 		str.update(comment_start, comment_end, '');
 	}
@@ -1673,6 +1672,11 @@ function extract_type_and_comment(declarator, state, path) {
 		state.has_type_or_fallback = true;
 		const match = /@type {(.+)}/.exec(comment_node.value);
 		if (match) {
+			// try to find JSDoc comments after a hyphen `-`
+			const jsdocComment = /@type {.+} (?:\w+|\[.*?\]) - (.+)/.exec(comment_node.value);
+			if (jsdocComment) {
+				cleaned_comment += jsdocComment[1]?.trim();
+			}
 			return {
 				type: match[1],
 				comment: cleaned_comment,
@@ -1693,7 +1697,6 @@ function extract_type_and_comment(declarator, state, path) {
 			};
 		}
 	}
-
 	return {
 		type: 'any',
 		comment: state.uses_ts ? comment : cleaned_comment,
diff --git a/packages/svelte/tests/migrate/samples/jsdoc-with-comments/input.svelte b/packages/svelte/tests/migrate/samples/jsdoc-with-comments/input.svelte
index f2efb1db80..f138c3a070 100644
--- a/packages/svelte/tests/migrate/samples/jsdoc-with-comments/input.svelte
+++ b/packages/svelte/tests/migrate/samples/jsdoc-with-comments/input.svelte
@@ -21,6 +21,9 @@
 	 */
 	export let type_no_comment;
 
+	/** @type {boolean} type_with_comment - One-line declaration with comment */
+	export let type_with_comment;
+
 	/**
 	 * This is optional
 	 */
@@ -40,4 +43,10 @@
 	export let inline_multiline_trailing_comment = 'world'; /*
 	* this is a same-line trailing multiline comment
 	**/
+
+	/** @type {number} [default_value=1] */
+	export let default_value = 1;
+
+	/** @type {number} [comment_default_value=1] - This has a comment and an optional value. */
+	export let comment_default_value = 1;
 </script>
\ No newline at end of file
diff --git a/packages/svelte/tests/migrate/samples/jsdoc-with-comments/output.svelte b/packages/svelte/tests/migrate/samples/jsdoc-with-comments/output.svelte
index 19fbe38b50..32133ccd4c 100644
--- a/packages/svelte/tests/migrate/samples/jsdoc-with-comments/output.svelte
+++ b/packages/svelte/tests/migrate/samples/jsdoc-with-comments/output.svelte
@@ -9,12 +9,18 @@
 	
 
 	
+
+	
+	
+
 	
 
 	
 
+
 	
 
+	
 	/**
 	 * @typedef {Object} Props
 	 * @property {string} comment - My wonderful comment
@@ -22,11 +28,14 @@
 	 * @property {any} one_line - one line comment
 	 * @property {any} no_comment
 	 * @property {boolean} type_no_comment
+	 * @property {boolean} type_with_comment - One-line declaration with comment
 	 * @property {any} [optional] - This is optional
 	 * @property {any} inline_commented - this should stay a comment
 	 * @property {any} inline_commented_merged - This comment should be merged - with this inline comment
 	 * @property {string} [inline_multiline_leading_comment] - this is a same-line leading multiline comment
 	 * @property {string} [inline_multiline_trailing_comment] - this is a same-line trailing multiline comment
+	 * @property {number} [default_value]
+	 * @property {number} [comment_default_value] - This has a comment and an optional value.
 	 */
 
 	/** @type {Props} */
@@ -36,10 +45,13 @@
 		one_line,
 		no_comment,
 		type_no_comment,
+		type_with_comment,
 		optional = {stuff: true},
 		inline_commented,
 		inline_commented_merged,
 		inline_multiline_leading_comment = 'world',
-		inline_multiline_trailing_comment = 'world'
+		inline_multiline_trailing_comment = 'world',
+		default_value = 1,
+		comment_default_value = 1
 	} = $props();
 </script>
\ No newline at end of file