fix(parser): allow escaped type names in import and export specifiers (#26487)

Allow escaped value names such as `import { t\u0079pe as x } from "m"` and the equivalent named exports. Reject escapes only after resolving `type` as a type-only modifier.

Preserve the decoded identifier name in the ambiguous `type as as` form so its AST name remains `type`.
This commit is contained in:
camc314
2026-09-09 13:22:34 +00:00
parent 2dcee2f216
commit c8e5fa7656
11 changed files with 80 additions and 19 deletions
+2 -6
View File
@@ -873,11 +873,7 @@ impl<'a, C: Config> ParserImpl<'a, C> {
can_parse_as_keyword = false;
} else {
// { type as as }
property_name = Some(ModuleExportName::new_identifier_name(
type_or_name_token.span(),
self.ident(self.token_source(&type_or_name_token)),
self,
));
property_name = Some(name);
name = ModuleExportName::new_identifier_name(
second_as.span,
second_as.name,
@@ -913,7 +909,7 @@ impl<'a, C: Config> ParserImpl<'a, C> {
name = self.parse_module_export_name();
}
if self.is_ts && type_or_name_token_kind == Kind::Type && type_or_name_token.escaped() {
if kind == ImportOrExportKind::Type && type_or_name_token.escaped() {
self.error(diagnostics::escaped_keyword(type_or_name_token.span()));
}
@@ -0,0 +1,6 @@
import { t\u0079pe as as x } from "m";
export { t\u0079pe Foo };
export { t\u0079pe as };
export { t\u0079pe as as x };
export { t\u0079pe Foo } from "m";
export { t\u0079pe as as x } from "m";
@@ -0,0 +1,5 @@
const type = 0;
export { t\u0079pe };
export { t\u0079pe as x };
export { t\u0079pe as as };
export type { t\u0079pe as T };
@@ -0,0 +1,4 @@
import { t\u0079pe } from "m";
import { t\u0079pe as x } from "m";
import { t\u0079pe as as } from "m";
import type { t\u0079pe as T } from "m";
@@ -0,0 +1,4 @@
export { t\u0079pe } from "m";
export { t\u0079pe as x } from "m";
export { t\u0079pe as as } from "m";
export type { t\u0079pe as T } from "m";
+2 -2
View File
@@ -1,3 +1,3 @@
codegen_misc Summary:
AST Parsed : 93/93 (100.00%)
Positive Passed: 93/93 (100.00%)
AST Parsed : 96/96 (100.00%)
Positive Passed: 96/96 (100.00%)
+2 -2
View File
@@ -1,3 +1,3 @@
formatter_misc Summary:
AST Parsed : 93/93 (100.00%)
Positive Passed: 93/93 (100.00%)
AST Parsed : 96/96 (100.00%)
Positive Passed: 96/96 (100.00%)
+2 -2
View File
@@ -1,3 +1,3 @@
lexer_misc Summary:
AST Parsed : 290/290 (100.00%)
Positive Passed: 290/290 (100.00%)
AST Parsed : 294/294 (100.00%)
Positive Passed: 294/294 (100.00%)
+49 -3
View File
@@ -1,7 +1,7 @@
parser_misc Summary:
AST Parsed : 93/93 (100.00%)
Positive Passed: 93/93 (100.00%)
Negative Passed: 197/197 (100.00%)
AST Parsed : 96/96 (100.00%)
Positive Passed: 96/96 (100.00%)
Negative Passed: 198/198 (100.00%)
× Cannot assign to 'arguments' in strict mode
╭─[misc/fail/arguments-eval-ambient.ts:2:13]
@@ -427,6 +427,52 @@ Negative Passed: 197/197 (100.00%)
· ─────────
╰────
× Keywords cannot contain escape characters
╭─[misc/fail/escaped-type-specifier.ts:1:10]
1 │ import { t\u0079pe as as x } from "m";
· ─────────
2 │ export { t\u0079pe Foo };
╰────
× Keywords cannot contain escape characters
╭─[misc/fail/escaped-type-specifier.ts:2:10]
1 │ import { t\u0079pe as as x } from "m";
2 │ export { t\u0079pe Foo };
· ─────────
3 │ export { t\u0079pe as };
╰────
× Keywords cannot contain escape characters
╭─[misc/fail/escaped-type-specifier.ts:3:10]
2 │ export { t\u0079pe Foo };
3 │ export { t\u0079pe as };
· ─────────
4 │ export { t\u0079pe as as x };
╰────
× Keywords cannot contain escape characters
╭─[misc/fail/escaped-type-specifier.ts:4:10]
3 │ export { t\u0079pe as };
4 │ export { t\u0079pe as as x };
· ─────────
5 │ export { t\u0079pe Foo } from "m";
╰────
× Keywords cannot contain escape characters
╭─[misc/fail/escaped-type-specifier.ts:5:10]
4 │ export { t\u0079pe as as x };
5 │ export { t\u0079pe Foo } from "m";
· ─────────
6 │ export { t\u0079pe as as x } from "m";
╰────
× Keywords cannot contain escape characters
╭─[misc/fail/escaped-type-specifier.ts:6:10]
5 │ export { t\u0079pe Foo } from "m";
6 │ export { t\u0079pe as as x } from "m";
· ─────────
╰────
× A unary expression with the '-' operator cannot be used as the left operand of an exponentiation expression
╭─[misc/fail/exponentiation-left-operands.ts:1:1]
1 │ -value ** 2;
+2 -2
View File
@@ -1,6 +1,6 @@
semantic_misc Summary:
AST Parsed : 93/93 (100.00%)
Positive Passed: 89/93 (95.70%)
AST Parsed : 96/96 (100.00%)
Positive Passed: 92/96 (95.83%)
semantic Error: tasks/coverage/misc/pass/declare-let-private.ts
Bindings mismatch:
after transform: ScopeId(0): ["private"]
@@ -1,3 +1,3 @@
transformer_misc Summary:
AST Parsed : 93/93 (100.00%)
Positive Passed: 93/93 (100.00%)
AST Parsed : 96/96 (100.00%)
Positive Passed: 96/96 (100.00%)