Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion packages/analysis/src/static/Parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import Lexer from './Lexer';
import Coder from './Coder';

const DEFAULT_IDENTIFIER = 'default';
const EXPORTED_PREFIX = '$_EXPORT';

export default class Parser
{
Expand Down Expand Up @@ -384,7 +385,7 @@ export default class Parser
{
// Default exports of values need to move to their own declaration

const identifier = `$_EXPORT_${token.start}_${token.end}`;
const identifier = `${EXPORTED_PREFIX}_${token.start}_${token.end}`;

tokenList.insert(
new Token(TokenType.KEYWORD, Keyword.CONST, 0, 0),
Expand All @@ -405,6 +406,25 @@ export default class Parser
{
token = tokenList.step(); // Read away the declaration keyword
stepSize++;

if (token.hasValue(Indicator.GENERATOR))
{
token = tokenList.step(); // Read away the generator indicator
stepSize++;
}
}

if (token.hasValue(Keyword.EXTENDS)
|| token.hasValue(Group.OPEN)
|| token.hasValue(Scope.OPEN))
{
// Anonymous functions and class need an identifier

const identifier = `${EXPORTED_PREFIX}_${token.start}_${token.end}`;

tokenList.insert(new Token(TokenType.IDENTIFIER, identifier, 0, 0));
Comment on lines +417 to +425

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Restrict synthetic names to declaration exports.

Lines 417-425 also match non-declaration expressions such as export default { value: 1 } and export default async () => 1. They receive an exported $_EXPORT_* name, but no corresponding declaration is inserted, leaving resolution with a nonexistent FQN. Gate this branch on having consumed a function or class declaration; route expression forms through the value-rehoming path instead.

Proposed fix
+        let hasDeclarationKeyword = false;
+
         if (isDeclaration(token.value))
         {
+            hasDeclarationKeyword = true;
             token = tokenList.step(); // Read away the declaration keyword
             stepSize++;
         }

-        if (token.hasValue(Keyword.EXTENDS)
+        if (hasDeclarationKeyword
+         && (token.hasValue(Keyword.EXTENDS)
          || token.hasValue(Group.OPEN)
-         || token.hasValue(Scope.OPEN))
+         || token.hasValue(Scope.OPEN)))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (token.hasValue(Keyword.EXTENDS)
|| token.hasValue(Group.OPEN)
|| token.hasValue(Scope.OPEN))
{
// Anonymous functions and class need an identifier
const identifier = `${EXPORTED_PREFIX}_${token.start}_${token.end}`;
tokenList.insert(new Token(TokenType.IDENTIFIER, identifier, 0, 0));
let hasDeclarationKeyword = false;
if (isDeclaration(token.value))
{
hasDeclarationKeyword = true;
token = tokenList.step(); // Read away the declaration keyword
stepSize++;
}
if (hasDeclarationKeyword
&& (token.hasValue(Keyword.EXTENDS)
|| token.hasValue(Group.OPEN)
|| token.hasValue(Scope.OPEN)))
{
// Anonymous functions and class need an identifier
const identifier = `${EXPORTED_PREFIX}_${token.start}_${token.end}`;
tokenList.insert(new Token(TokenType.IDENTIFIER, identifier, 0, 0));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/analysis/src/static/Parser.ts` around lines 417 - 425, Restrict the
synthetic identifier insertion in the export-handling branch to cases where the
parser has consumed a function or class declaration. Ensure expression exports
such as object literals and arrow functions bypass this branch and use the
existing value-rehoming path, while preserving synthetic names for anonymous
function and class declarations.


token = tokenList.current;
}

const identifier = this.#isIdentifier(token) ? token.value : '';
Expand Down
6 changes: 5 additions & 1 deletion packages/analysis/src/static/definitions/Keyword.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ const Keyword =
THROW: 'throw',
TRY: 'try',
CATCH: 'catch',
FINALLY: 'finally'
FINALLY: 'finally',

// TYPE CHECKING
TYPEOF: 'typeof',
INSTANCEOF: 'instanceof'
};

const Keywords = Object.values(Keyword);
Expand Down
4 changes: 2 additions & 2 deletions packages/analysis/test/static/Parser.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ describe('Parser', () =>
expect(exported.from).toBeUndefined();

const member = exported.members[0];
expect(member.identifier).toEqual('');
expect(member.identifier).toEqual('$_EXPORT_23_23');
expect(member.alias).toEqual('default');

const declaration = module.statements[1] as ESFunction;
Expand All @@ -368,7 +368,7 @@ describe('Parser', () =>
expect(exported.from).toBeUndefined();

const member = exported.members[0];
expect(member.identifier).toEqual('');
expect(member.identifier).toEqual('$_EXPORT_21_21');
expect(member.alias).toEqual('default');

const declaration = module.statements[1] as ESClass;
Expand Down
Loading