Repository: terser/terser (JavaScript)

Issue:
Unitialized const declaration when minifying in module mode from spidermonkey ast
_Preface: This sounds very similar to #1596, but since that issue does not mention the used terser parameters (especially requirements like spidermonkey AST), I think this might be the same issue but could also be another one, therefore I create this issue separately._

When minifying with `module: true` from spidermonkey ast, created by `acron` parser, inlined const statements inside conditions are not properly removed. This issue does not happen when the same code is parsed by terser directly, without the spidermonkey AST to terser AST conversion.

Production code that triggers this: https://github.com/TYPO3/typo3/blob/69139463222/Build/Sources/TypeScript/core/java-script-item-handler.ts#L19-L22 in an attempt to switch to spidermonkey AST based terser usage: https://review.typo3.org/c/Packages/TYPO3.CMS/+/88272/3

Our CI revealed that invalid code is generated and raises a JavaScript error once parsed by browsers:
```
Uncaught SyntaxError: Missing initializer in const declaration
```

Reduced to a minimal example:
```
if (a) {
  const tmp = a;
  tmp.b();
}
```

Invalid terser output:
```
if(a){const b;a.b()}
//          ^
// triggers: Uncaught SyntaxError: Missing initializer in const declaration
```

Expected terser output:
```
if(a){a.b()}
```


Minimal reproducible terser/acorn usage:

```
import { parse } from 'acorn';
import { minify } from 'terser';

const example = `
  if (a) {
    const tmp = a;
    tmp.b();
  }
`;

const ast = parse(example, { sourceType: 'module', ecmaVersion: 2023, locations: true })
const invalid = await minify(ast, { ecma: 2020, module: true, parse: { spidermonkey: true } });
// Outputs: { code: 'if(a){const b;a.b()}' }
console.log(invalid);

// Using terser parser directly resolved to a valid minifcation result
const valid = await minify(example, { ecma: 2020, module: true });
// Outputs: { code: 'if(a){a.b()}' }
console.log(valid);
```


Discussion:

Patch:
diff --git a/lib/mozilla-ast.js b/lib/mozilla-ast.js
index 589617b38..e94555b49 100644
--- a/lib/mozilla-ast.js
+++ b/lib/mozilla-ast.js
@@ -730,8 +730,9 @@ import { is_basic_identifier_string } from "./parse.js";
 
         Identifier: function(M) {
             var p = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 2];
+            var q = FROM_MOZ_STACK[FROM_MOZ_STACK.length - 3];
             return new (  p.type == "LabeledStatement" ? AST_Label
-                        : p.type == "VariableDeclarator" && p.id === M ? (p.kind == "const" ? AST_SymbolConst : p.kind == "let" ? AST_SymbolLet : AST_SymbolVar)
+                        : p.type == "VariableDeclarator" && p.id === M ? (q.kind == "const" ? AST_SymbolConst : q.kind == "let" ? AST_SymbolLet : AST_SymbolVar)
                         : /Import.*Specifier/.test(p.type) ? (p.local === M ? AST_SymbolImport : AST_SymbolImportForeign)
                         : p.type == "ExportSpecifier" ? (p.local === M ? AST_SymbolExport : AST_SymbolExportForeign)
                         : p.type == "FunctionExpression" ? (p.id === M ? AST_SymbolLambda : AST_SymbolFunarg)


Test patch:
diff --git a/test/mocha/spidermonkey.js b/test/mocha/spidermonkey.js
index 411e5a0d3..96338355b 100644
--- a/test/mocha/spidermonkey.js
+++ b/test/mocha/spidermonkey.js
@@ -145,6 +145,21 @@ describe("spidermonkey export/import sanity test", function() {
         );
     });
 
+    it("should correctly minify spidermonkey AST with condition and inlineable const variable declaration", async () => {
+        const code = "if (a) { const tmp = a; tmp.b(); }";
+        const ast = acornParse(code, { sourceType: 'module', locations: true, ecmaVersion: 2015 });
+        const result = await minify(ast, { ecma: 2015, module: true, parse: { spidermonkey: true } });
+        assert.strictEqual(
+            result.code,
+            "if(a){a.b()}"
+        );
+        const vanilla = await minify(code, { ecma: 2015, module: true });
+        assert.strictEqual(
+            result.code,
+            vanilla.code
+        );
+    });
+
     it("should correctly minify AST from from_moz_ast with default function parameter", async () => {
         const code = "function run(x = 2){}";
         const acornAst = acornParse(code, { locations: true, ecmaVersion: 2023 });