Repository: sveltejs/language-tools
Pull request #1483 (2022-05-13 14:57:56)

(fix) better mapping for empty text attribute
new transformation
#1352


Patch:
diff --git a/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/Attribute.ts b/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/Attribute.ts
index 15881f83..d8a82ea5 100644
--- a/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/Attribute.ts
+++ b/packages/svelte2tsx/src/htmlxtojsx_v2/nodes/Attribute.ts
@@ -139,7 +139,7 @@ export function handleAttribute(
         return;
     }
     if (attr.value.length == 0) {
-        // attr=""
+        // shouldn't happen
         addAttribute(attributeName, ['""']);
         return;
     }
@@ -148,6 +148,12 @@ export function handleAttribute(
         const attrVal = attr.value[0];
 
         if (attrVal.type == 'Text') {
+            // Handle the attr="" special case with a transformation that allows mapping of the position
+            if (attrVal.start === attrVal.end) {
+                addAttribute(attributeName, [[attrVal.start - 1, attrVal.end + 1]]);
+                return;
+            }
+
             const hasBrackets =
                 str.original.lastIndexOf('}', attrVal.end) === attrVal.end - 1 ||
                 str.original.lastIndexOf('}"', attrVal.end) === attrVal.end - 1 ||


Test patch:
diff --git a/packages/language-server/test/plugins/typescript/features/CompletionProvider.test.ts b/packages/language-server/test/plugins/typescript/features/CompletionProvider.test.ts
index 039e5282..77c4e92d 100644
--- a/packages/language-server/test/plugins/typescript/features/CompletionProvider.test.ts
+++ b/packages/language-server/test/plugins/typescript/features/CompletionProvider.test.ts
@@ -1306,6 +1306,19 @@ function test(useNewTransformation: boolean) {
             }
         });
 
+        it('handles completion in empty text attribute', async () => {
+            const { completionProvider, document } = setup('emptytext-importer.svelte');
+
+            const completions = await completionProvider.getCompletions(
+                document,
+                Position.create(4, 14)
+            );
+            assert.deepStrictEqual(
+                completions?.items.map((item) => item.label),
+                ['s', 'm', 'l']
+            );
+        });
+
         // Hacky, but it works. Needed due to testing both new and old transformation
         after(() => {
             __resetCache();
diff --git a/packages/language-server/test/plugins/typescript/testfiles/completions/emptytext-imported.svelte b/packages/language-server/test/plugins/typescript/testfiles/completions/emptytext-imported.svelte
new file mode 100644
index 00000000..3f65cd7d
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/testfiles/completions/emptytext-imported.svelte
@@ -0,0 +1,3 @@
+<script lang="ts">
+	export let size: 's' | 'm' | 'l';
+</script>
diff --git a/packages/language-server/test/plugins/typescript/testfiles/completions/emptytext-importer.svelte b/packages/language-server/test/plugins/typescript/testfiles/completions/emptytext-importer.svelte
new file mode 100644
index 00000000..1ba6a4d9
--- /dev/null
+++ b/packages/language-server/test/plugins/typescript/testfiles/completions/emptytext-importer.svelte
@@ -0,0 +1,5 @@
+<script>
+	import Button from './emptytext-imported.svelte';
+</script>
+
+<Button size="" />
diff --git a/packages/svelte2tsx/test/htmlx2jsx/samples/component-slot-infer-props/expectedv2.js b/packages/svelte2tsx/test/htmlx2jsx/samples/component-slot-infer-props/expectedv2.js
index 3d2fe0f5..7f5ea732 100644
--- a/packages/svelte2tsx/test/htmlx2jsx/samples/component-slot-infer-props/expectedv2.js
+++ b/packages/svelte2tsx/test/htmlx2jsx/samples/component-slot-infer-props/expectedv2.js
@@ -1,4 +1,4 @@
- { const $$_Parent0C = __sveltets_2_ensureComponent(Parent); const $$_Parent0 = new $$_Parent0C({ target: __sveltets_2_any(), props: {                 "bare":true,shorthand,"text1":`val1`,"text2":`val2`,"text3":`a${a}b${b}`,"textEmpty":``,"literal":true,"strLiteral":'foo',"complex":{a},"a-dashed-complex":{a},...__sveltets_2_cssProp({"--custom-cssprop":`foo`}),}});{const {/*Ωignore_startΩ*/$$_$$/*Ωignore_endΩ*/,foo,} = $$_Parent0.$$slot_def.default;$$_$$;
+ { const $$_Parent0C = __sveltets_2_ensureComponent(Parent); const $$_Parent0 = new $$_Parent0C({ target: __sveltets_2_any(), props: {                "bare":true,shorthand,"text1":`val1`,"text2":`val2`,"text3":`a${a}b${b}`,"textEmpty":"","literal":true,"strLiteral":'foo',"complex":{a},"a-dashed-complex":{a},...__sveltets_2_cssProp({"--custom-cssprop":`foo`}),}});{const {/*Ωignore_startΩ*/$$_$$/*Ωignore_endΩ*/,foo,} = $$_Parent0.$$slot_def.default;$$_$$;
      {const {/*Ωignore_startΩ*/$$_$$/*Ωignore_endΩ*/,bar,} = $$_Parent0.$$slot_def["named"];$$_$$;{ const $$_Component1C = __sveltets_2_ensureComponent(Component); new $$_Component1C({ target: __sveltets_2_any(), props: {  }});
         foo; bar;
      }Component}
diff --git a/packages/svelte2tsx/test/htmlx2jsx/samples/event-handler-component-infer-props/expectedv2.js b/packages/svelte2tsx/test/htmlx2jsx/samples/event-handler-component-infer-props/expectedv2.js
index a414fcc6..f880af8d 100644
--- a/packages/svelte2tsx/test/htmlx2jsx/samples/event-handler-component-infer-props/expectedv2.js
+++ b/packages/svelte2tsx/test/htmlx2jsx/samples/event-handler-component-infer-props/expectedv2.js
@@ -1,1 +1,1 @@
- { const $$_Component0C = __sveltets_2_ensureComponent(Component); const $$_Component0 = new $$_Component0C({ target: __sveltets_2_any(), props: {                   "bare":true,shorthand,"text1":`val1`,"text2":`val2`,"text3":`a${a}b${b}`,"textEmpty":``,"literal":true,"strLiteral":'foo',"complex":{a},"a-dashed-complex":{a},...__sveltets_2_cssProp({"--custom-cssprop":`foo`}),}});$$_Component0.$on("click", e => e);}
\ No newline at end of file
+ { const $$_Component0C = __sveltets_2_ensureComponent(Component); const $$_Component0 = new $$_Component0C({ target: __sveltets_2_any(), props: {                  "bare":true,shorthand,"text1":`val1`,"text2":`val2`,"text3":`a${a}b${b}`,"textEmpty":"","literal":true,"strLiteral":'foo',"complex":{a},"a-dashed-complex":{a},...__sveltets_2_cssProp({"--custom-cssprop":`foo`}),}});$$_Component0.$on("click", e => e);}
\ No newline at end of file
diff --git a/packages/svelte2tsx/test/svelte2tsx/samples/style-after-selfclosing-iframe/expectedv2.ts b/packages/svelte2tsx/test/svelte2tsx/samples/style-after-selfclosing-iframe/expectedv2.ts
index 93e85b4e..a1ea21c3 100644
--- a/packages/svelte2tsx/test/svelte2tsx/samples/style-after-selfclosing-iframe/expectedv2.ts
+++ b/packages/svelte2tsx/test/svelte2tsx/samples/style-after-selfclosing-iframe/expectedv2.ts
@@ -1,6 +1,6 @@
 ///<reference types="svelte" />
 ;function render() {
-async () => { { svelteHTML.createElement("iframe", { "src":``,});}
+async () => {  { svelteHTML.createElement("iframe", {"src":"",});}
 };
 return { props: {}, slots: {}, getters: {}, events: {} }}