Skip to content

Fix source type detection when parsing TypeScript #17107

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 21, 2025

Conversation

JLHwung
Copy link
Contributor

@JLHwung JLHwung commented Feb 4, 2025

Q                       A
Fixed Issues? parsing export { a } with typescript plugin and unambiguous source type does not set program sourceType to module (part of #16679)
Patch: Bug Fix?
Major: Breaking Change?
Minor: New Feature?
Tests Added + Pass? Yes
Documentation PR Link
Any Dependency Changes?
License MIT

This issue surfaces when we are aligning to the typescript-eslint AST. The typescript parser plugin called super.parseExport without handling the sawUnambiguousESM state, here we moved the state handling into parseExport so it should work for both JS and TS.

@JLHwung JLHwung added PR: Bug Fix 🐛 A type of pull request used for our changelog categories pkg: parser labels Feb 4, 2025
@babel-bot
Copy link
Collaborator

babel-bot commented Feb 4, 2025

Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/58671

@@ -2374,6 +2364,10 @@ export default abstract class StatementParser extends ExpressionParser {
}
this.parseExportFrom(node, true);

if (node.exportKind !== "type") {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here is one thing typescript-eslint differs: they set the sourceType to module even when the source only includes type imports/exports: AFAIK TS does not offer ways to include types via commonJS require, so I am not convinced that we should do so as well. To align with their AST we can monkey patch the eslint-parser instead.

@bradzacher Could you shred some light here? Thank you.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's actually entirely correct to treat the file as a module if it only contains only type-only import -- it's the same behaviour that TS itself exhibits.

For example you can see in this playground.

  1. the emitted JS code is export {};
  2. there is no error on the Map interface (see below)

But if you comment out the type-only import then:

  1. the emitted JS code is instead "use strict"; as it's no longer treated as an ESM file
  2. there is an error on the Map interface as TS is trying to declaration merge with the global type.

So yeah -- our behaviour is aligned with TS itself.

Copy link
Contributor

Choose a reason for hiding this comment

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

AFAIK TS does not offer ways to include types via commonJS require

It does, but not in the same "type only" fashion.

// module.ts
namespace Foo {
  export type T = number;
}
export = Foo;

// other.ts
import Foo = require('./module');

type T = Foo.T;

It's much more cumbersome, but still valid.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@bradzacher Thank you for your detailed explanation, from which I have learned a lot. In that case I think we will align to TS as well.

@@ -4,7 +4,7 @@
"program": {
"type": "Program",
"start":0,"end":78,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":25,"index":78}},
"sourceType": "script",
"sourceType": "module",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This PR also changes the flow handling. As we can see from the playground, both

import react from "react";
const yield = 1;

and

import type react from "react";
const yield = 1;

are accepted, which means flow does not set the script type based on imports. So we already deviated from the flow behaviour for non-type imports.

@JLHwung JLHwung merged commit 1432002 into babel:main Feb 21, 2025
55 checks passed
@JLHwung JLHwung deleted the fix-ts-unambiguous-esm-export-named branch February 21, 2025 14:35
laine-hallot pushed a commit to laine-hallot/uwu-parser that referenced this pull request Mar 31, 2025
* add new test cases

* fix: move sawUnambiguousESM to parseExport

* fix: set sawUnambiguousESM on type imports

* update test fixtures
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg: parser PR: Bug Fix 🐛 A type of pull request used for our changelog categories
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants