]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-sfc): fix binding analysis for aliased late import
authorEvan You <yyx990803@gmail.com>
Tue, 8 Nov 2022 09:19:45 +0000 (17:19 +0800)
committerEvan You <yyx990803@gmail.com>
Tue, 8 Nov 2022 09:19:45 +0000 (17:19 +0800)
packages/compiler-sfc/__tests__/compileScript.spec.ts
packages/compiler-sfc/src/compileScript.ts

index 5c03ac17fdbdb2ded562ac26931db2b1251291c9..96160e272d53232886a1fe2bcd0cd5905415ff5b 100644 (file)
@@ -391,6 +391,19 @@ defineExpose({ foo: 123 })
           bar: BindingTypes.SETUP_REACTIVE_CONST
         })
       })
+
+      test('aliased usage before import site', () => {
+        const { bindings } = compile(`
+        <script setup>
+          const bar = x(1)
+          import { reactive as x } from 'vue'
+        </script>
+      `)
+        expect(bindings).toStrictEqual({
+          bar: BindingTypes.SETUP_REACTIVE_CONST,
+          x: BindingTypes.SETUP_CONST
+        })
+      })
     })
   })
 
index adc22ab6820ce35cd96c17aa0ba812e7bbf7f8a3..ccf670725ec0a8fc5d46b80a9974e25fd68ce3de 100644 (file)
@@ -354,6 +354,25 @@ export function compileScript(
     )
   }
 
+  function hoistNode(node: Statement) {
+    const start = node.start! + startOffset
+    let end = node.end! + startOffset
+    // locate comment
+    if (node.trailingComments && node.trailingComments.length > 0) {
+      const lastCommentNode =
+        node.trailingComments[node.trailingComments.length - 1]
+      end = lastCommentNode.end + startOffset
+    }
+    // locate the end of whitespace between this statement and the next
+    while (end <= source.length) {
+      if (!/\s/.test(source.charAt(end))) {
+        break
+      }
+      end++
+    }
+    s.move(start, end, 0)
+  }
+
   function registerUserImport(
     source: string,
     local: string,
@@ -891,6 +910,7 @@ export function compileScript(
       scriptStartOffset!
     )
 
+    // walk import declarations first
     for (const node of scriptAst.body) {
       if (node.type === 'ImportDeclaration') {
         // record imports for dedupe
@@ -910,7 +930,11 @@ export function compileScript(
             !options.inlineTemplate
           )
         }
-      } else if (node.type === 'ExportDefaultDeclaration') {
+      }
+    }
+
+    for (const node of scriptAst.body) {
+      if (node.type === 'ExportDefaultDeclaration') {
         // export default
         defaultExport = node
 
@@ -1040,39 +1064,9 @@ export function compileScript(
   )
 
   for (const node of scriptSetupAst.body) {
-    const start = node.start! + startOffset
-    let end = node.end! + startOffset
-    // locate comment
-    if (node.trailingComments && node.trailingComments.length > 0) {
-      const lastCommentNode =
-        node.trailingComments[node.trailingComments.length - 1]
-      end = lastCommentNode.end + startOffset
-    }
-    // locate the end of whitespace between this statement and the next
-    while (end <= source.length) {
-      if (!/\s/.test(source.charAt(end))) {
-        break
-      }
-      end++
-    }
-
-    // (Dropped) `ref: x` bindings
-    if (
-      node.type === 'LabeledStatement' &&
-      node.label.name === 'ref' &&
-      node.body.type === 'ExpressionStatement'
-    ) {
-      error(
-        `ref sugar using the label syntax was an experimental proposal and ` +
-          `has been dropped based on community feedback. Please check out ` +
-          `the new proposal at https://github.com/vuejs/rfcs/discussions/369`,
-        node
-      )
-    }
-
     if (node.type === 'ImportDeclaration') {
       // import declarations are moved to top
-      s.move(start, end, 0)
+      hoistNode(node)
 
       // dedupe imports
       let removed = 0
@@ -1137,6 +1131,26 @@ export function compileScript(
         s.remove(node.start! + startOffset, node.end! + startOffset)
       }
     }
+  }
+
+  for (const node of scriptSetupAst.body) {
+    // already processed
+    if (node.type === 'ImportDeclaration') continue
+
+    // (Dropped) `ref: x` bindings
+    // TODO remove when out of experimental
+    if (
+      node.type === 'LabeledStatement' &&
+      node.label.name === 'ref' &&
+      node.body.type === 'ExpressionStatement'
+    ) {
+      error(
+        `ref sugar using the label syntax was an experimental proposal and ` +
+          `has been dropped based on community feedback. Please check out ` +
+          `the new proposal at https://github.com/vuejs/rfcs/discussions/369`,
+        node
+      )
+    }
 
     if (node.type === 'ExpressionStatement') {
       // process `defineProps` and `defineEmit(s)` calls
@@ -1268,7 +1282,7 @@ export function compileScript(
         (node.type === 'VariableDeclaration' && node.declare)
       ) {
         recordType(node, declaredTypes)
-        s.move(start, end, 0)
+        hoistNode(node)
       }
     }
   }