Repository: sveltejs/language-tools
Pull request #1960 (2023-03-23 16:06:17)

(fix) swap order of inserted statements for store prop with type
#1950


Patch:
diff --git a/packages/svelte2tsx/src/svelte2tsx/nodes/ImplicitStoreValues.ts b/packages/svelte2tsx/src/svelte2tsx/nodes/ImplicitStoreValues.ts
index 799a4d6a..881053fc 100644
--- a/packages/svelte2tsx/src/svelte2tsx/nodes/ImplicitStoreValues.ts
+++ b/packages/svelte2tsx/src/svelte2tsx/nodes/ImplicitStoreValues.ts
@@ -1,7 +1,7 @@
 import MagicString from 'magic-string';
 import ts from 'typescript';
 import { surroundWithIgnoreComments } from '../../utils/ignore';
-import { preprendStr } from '../../utils/magic-string';
+import { getCurrentPrepends, preprendStr } from '../../utils/magic-string';
 import { extractIdentifiers, getNamesFromLabeledStatement } from '../utils/tsAst';
 
 /**
@@ -69,7 +69,15 @@ export class ImplicitStoreValues {
                 ? node.parent.declarations[node.parent.declarations.length - 1].getEnd()
                 : node.getEnd();
 
-        str.appendRight(nodeEnd + astOffset, storeDeclarations);
+        // Quick-fixing https://github.com/sveltejs/language-tools/issues/1950
+        // TODO think about a SourceMap-wrapper that does these things for us,
+        // or investigate altering the inner workings of SourceMap, or investigate
+        // if we can always use prependStr here (and elsewhere, too)
+        if (getCurrentPrepends(str, nodeEnd + astOffset).length) {
+            preprendStr(str, nodeEnd + astOffset, storeDeclarations);
+        } else {
+            str.appendRight(nodeEnd + astOffset, storeDeclarations);
+        }
     }
 
     private attachStoreValueDeclarationToReactiveAssignment(
@@ -89,9 +97,10 @@ export class ImplicitStoreValues {
         );
         const endPos = node.getEnd() + astOffset;
 
-        // Hack for quick-fixing https://github.com/sveltejs/language-tools/issues/1097
+        // Quick-fixing https://github.com/sveltejs/language-tools/issues/1097
         // TODO think about a SourceMap-wrapper that does these things for us,
-        // or investigate altering the inner workings of SourceMap
+        // or investigate altering the inner workings of SourceMap, or investigate
+        // if we can always use prependStr here (and elsewhere, too)
         if (str.original.charAt(endPos - 1) !== ';') {
             preprendStr(str, endPos, storeDeclarations);
         } else {
diff --git a/packages/svelte2tsx/src/utils/magic-string.ts b/packages/svelte2tsx/src/utils/magic-string.ts
index 61f5b9d9..7369f142 100644
--- a/packages/svelte2tsx/src/utils/magic-string.ts
+++ b/packages/svelte2tsx/src/utils/magic-string.ts
@@ -39,9 +39,16 @@ function updatePrepends(
     toAppend: string,
     removeExisting?: boolean
 ): string[] {
-    (str as any).__prepends__ = (str as any).__prepends__ || new Map<string, string[]>();
+    (str as any).__prepends__ = (str as any).__prepends__ || new Map<number, string[]>();
     const prepends = removeExisting ? [] : (str as any).__prepends__.get(index) || [];
     prepends.push(toAppend);
     (str as any).__prepends__.set(index, prepends);
     return prepends;
 }
+
+/**
+ * Returns the prepends that were added at the given index (if any).
+ */
+export function getCurrentPrepends(str: MagicString, index: number): string[] {
+    return (str as any).__prepends__?.get(index) || [];
+}


Test patch:
diff --git a/packages/svelte2tsx/test/sourcemaps/samples/reactive-statements/mappings.jsx b/packages/svelte2tsx/test/sourcemaps/samples/reactive-statements/mappings.jsx
index 3b0d533c..8ef14e46 100644
--- a/packages/svelte2tsx/test/sourcemaps/samples/reactive-statements/mappings.jsx
+++ b/packages/svelte2tsx/test/sourcemaps/samples/reactive-statements/mappings.jsx
@@ -10,9 +10,9 @@
         ↲                                                                                                                                             
 <script>↲    [original] line 1 (rest generated at line 2)                                                                                             
 ------------------------------------------------------------------------------------------------------------------------------------------------------ */}
-     let prop/*Ωignore_startΩ*/;let $prop = __sveltets_2_store_get(prop);/*Ωignore_endΩ*//*Ωignore_startΩ*/;prop = __sveltets_2_any(prop);/*Ωignore_endΩ*/
-   ╚•let•prop/*Ωignore_startΩ*/;let•$prop•=•__sveltets_2_store_get(prop);/*Ωignore_endΩ*//*Ωignore_startΩ*/;prop•=•__sveltets_2_any(prop);/*Ωignore_endΩ*/↲    [generated] line 4
-   ╚•let•prop                                                                            ↲                                                                     
+     let prop/*Ωignore_startΩ*/;prop = __sveltets_2_any(prop);/*Ωignore_endΩ*//*Ωignore_startΩ*/;let $prop = __sveltets_2_store_get(prop);/*Ωignore_endΩ*/
+   ╚•let•prop/*Ωignore_startΩ*/;prop•=•__sveltets_2_any(prop);/*Ωignore_endΩ*//*Ωignore_startΩ*/;let•$prop•=•__sveltets_2_store_get(prop);/*Ωignore_endΩ*/↲    [generated] line 4
+   ╚•let•prop↲                                                                                                                                                 
    ╚      •let•prop↲                                                                                                                                           
    ╚export•let•prop↲                                                                                                                                           [original] line 2 
 //----------------------------------------------------------------------------------------------------------------------------------------------------
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/$store-export-type/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/$store-export-type/expectedv2.ts
new file mode 100644
index 00000000..a74198fb
--- /dev/null
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/$store-export-type/expectedv2.ts
@@ -0,0 +1,18 @@
+///<reference types="svelte" />
+;
+import type { Writable } from "svelte/store";
+function render() {
+
+    
+    
+     let store: Writable<string[]> | null = null/*Ωignore_startΩ*/;store = __sveltets_2_any(store);/*Ωignore_endΩ*//*Ωignore_startΩ*/;let $store = __sveltets_2_store_get(store);/*Ωignore_endΩ*/;
+    
+    if ($store) {
+        $store.length
+    }
+;
+async () => {};
+return { props: {store: store}, slots: {}, events: {} }}
+
+export default class Input__SvelteComponent_ extends __sveltets_2_createSvelte2TsxComponent(__sveltets_2_partial(['store'], __sveltets_2_with_any_event(render()))) {
+}
\ No newline at end of file
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/$store-export-type/input.svelte b/packages/svelte2tsx/test/svelte2tsx/samples/$store-export-type/input.svelte
new file mode 100644
index 00000000..9f6376c9
--- /dev/null
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/$store-export-type/input.svelte
@@ -0,0 +1,9 @@
+<script>
+    import type { Writable } from "svelte/store";
+    
+    export let store: Writable<string[]> | null = null;
+    
+    if ($store) {
+        $store.length
+    }
+</script>