Repository: parcel-bundler/parcel (js)

Issue:
`export default` of a global crashes
# 🐛 bug report

The hoist part of scope hoisting crashes if a global is exported.

Discovered in https://github.com/parcel-bundler/parcel/issues/4335


## 🤔 Expected Behavior

`123`

## 😯 Current Behavior

```js
@parcel/transformer-js: Got unexpected undefined
Error: Got unexpected undefined
    at nullthrows (parcel/node_modules/nullthrows/nullthrows.js:7:15)
    at safeRename (parcel/packages/shared/scope-hoisting/src/hoist.js:748:17)
    at MutableAsset.ExportDefaultDeclaration (parcel/packages/shared/scope-hoisting/src/hoist.js:558:7)
    at NodePath._call (parcel/node_modules/@babel/traverse/lib/path/context.js:55:20)
    at NodePath.call (parcel/node_modules/@babel/traverse/lib/path/context.js:42:17)
    at NodePath.visit (parcel/node_modules/@babel/traverse/lib/path/context.js:90:31)
    at TraversalContext.visitQueue (parcel/node_modules/@babel/traverse/lib/context.js:112:16)
    at TraversalContext.visitMultiple (parcel/node_modules/@babel/traverse/lib/context.js:79:17)
    at TraversalContext.visit (parcel/node_modules/@babel/traverse/lib/context.js:138:19)
    at Function.traverse.node (parcel/node_modules/@babel/traverse/lib/index.js:84:17)
```

## 💁 Possible Solution

Only rename if there is a binding.

## 💻 Code Sample

```js
// a.js
import b from "./b.js";

console.log(b("121") + 2);

// b.js
export default Number;
```

## 🌍 Your Environment

<!--- Include as many relevant details about the environment you experienced the bug in -->

| Software         | Version(s) |
| ---------------- | ---------- |
| Parcel           | 9007d6ac51a44cca44ff216ee103baca76be5504


Pull request description:
Fix crash when default exporting a global variable
# ↪️ Pull Request

Closes #4348

## 💻 Examples

```js
export default Number;
```


Patch:
diff --git a/packages/shared/scope-hoisting/src/hoist.js b/packages/shared/scope-hoisting/src/hoist.js
index 13822d7fe..a4ac3fddd 100644
--- a/packages/shared/scope-hoisting/src/hoist.js
+++ b/packages/shared/scope-hoisting/src/hoist.js
@@ -569,7 +569,7 @@ const VISITOR: Visitor<MutableAsset> = {
       }),
     );
 
-    if (isIdentifier(declaration)) {
+    if (isIdentifier(declaration) && path.scope.hasBinding(declaration.name)) {
       // Rename the variable being exported.
       safeRename(path, asset, declaration.name, identifier.name);
       path.remove();


Test patch:
diff --git a/packages/core/integration-tests/test/integration/scope-hoisting/es6/export-default-global/a.js b/packages/core/integration-tests/test/integration/scope-hoisting/es6/export-default-global/a.js
new file mode 100644
index 000000000..1c9964aff
--- /dev/null
+++ b/packages/core/integration-tests/test/integration/scope-hoisting/es6/export-default-global/a.js
@@ -0,0 +1,3 @@
+import b from "./b.js";
+
+output = b;
diff --git a/packages/core/integration-tests/test/integration/scope-hoisting/es6/export-default-global/b.js b/packages/core/integration-tests/test/integration/scope-hoisting/es6/export-default-global/b.js
new file mode 100644
index 000000000..27d82e74e
--- /dev/null
+++ b/packages/core/integration-tests/test/integration/scope-hoisting/es6/export-default-global/b.js
@@ -0,0 +1,1 @@
+export default Test;
diff --git a/packages/core/integration-tests/test/scope-hoisting.js b/packages/core/integration-tests/test/scope-hoisting.js
index 3ff78eb0f..dc46ea0f2 100644
--- a/packages/core/integration-tests/test/scope-hoisting.js
+++ b/packages/core/integration-tests/test/scope-hoisting.js
@@ -470,6 +470,20 @@ describe('scope hoisting', function() {
       assert.deepEqual(output, ['test']);
     });
 
+    it('should default export globals', async function() {
+      let b = await bundle(
+        path.join(
+          __dirname,
+          '/integration/scope-hoisting/es6/export-default-global/a.js',
+        ),
+      );
+
+      let Test = Symbol('Test');
+
+      let output = await run(b, {Test});
+      assert.strictEqual(output, Test);
+    });
+
     it('throws a meaningful error on undefined exports', async function() {
       let threw = false;
       try {