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
20 changes: 20 additions & 0 deletions crates/oxc_parser/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1284,3 +1284,23 @@ pub fn ts_import_type_options_invalid_key(span: Span) -> OxcDiagnostic {
pub fn ts_import_type_options_no_spread(span: Span) -> OxcDiagnostic {
OxcDiagnostic::error("Spread elements are not allowed in import type options.").with_label(span)
}

// This syntax is reserved in files with the .mts or .cts extension. Use an `as` expression instead. ts(7059)
#[cold]
pub fn jsx_type_assertion_in_mts_cts(span: Span) -> OxcDiagnostic {
ts_error(
"7059",
"This syntax is reserved in files with the .mts or .cts extension. Use an `as` expression instead.",
)
.with_label(span)
}

// This syntax is reserved in files with the .mts or .cts extension. Add a trailing comma or explicit constraint. ts(7060)
#[cold]
pub fn jsx_type_parameter_in_mts_cts(span: Span) -> OxcDiagnostic {
ts_error(
"7060",
"This syntax is reserved in files with the .mts or .cts extension. Add a trailing comma or explicit constraint.",
)
.with_label(span)
}
14 changes: 12 additions & 2 deletions crates/oxc_parser/src/js/arrow.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use oxc_allocator::Box;
use oxc_ast::{NONE, ast::*};
use oxc_span::GetSpan;
use oxc_span::{FileExtension, GetSpan};
use oxc_syntax::precedence::Precedence;

use super::{FunctionKind, Tristate};
Expand Down Expand Up @@ -252,7 +252,17 @@ impl<'a> ParserImpl<'a> {
let has_await = self.ctx.has_await();
self.ctx = self.ctx.union_await_if(r#async);

let type_parameters = self.parse_ts_type_parameters();
let (type_parameters, has_trailing_comma) =
self.parse_ts_type_parameters_with_trailing_comma();

if let Some(type_params) = &type_parameters
&& matches!(self.source_type.extension(), Some(FileExtension::Mts | FileExtension::Cts))
&& type_params.params.len() == 1
&& type_params.params[0].constraint.is_none()
&& !has_trailing_comma
{
self.error(diagnostics::jsx_type_parameter_in_mts_cts(type_params.params[0].name.span));
}

let (this_param, params) = self.parse_formal_parameters(
FunctionKind::Expression,
Expand Down
10 changes: 8 additions & 2 deletions crates/oxc_parser/src/ts/statement.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use oxc_allocator::{Box, Vec};
use oxc_ast::ast::*;
use oxc_span::GetSpan;
use oxc_span::{FileExtension, GetSpan};

use crate::{
Context, ParserImpl, diagnostics,
Expand Down Expand Up @@ -552,7 +552,13 @@ impl<'a> ParserImpl<'a> {
self.expect(Kind::RAngle);
let lhs_span = self.start_span();
let expression = self.parse_simple_unary_expression(lhs_span);
self.ast.expression_ts_type_assertion(self.end_span(span), type_annotation, expression)
let span = self.end_span(span);

if matches!(self.source_type.extension(), Some(FileExtension::Mts | FileExtension::Cts)) {
self.error(diagnostics::jsx_type_assertion_in_mts_cts(span));
}

self.ast.expression_ts_type_assertion(span, type_annotation, expression)
}

pub(crate) fn parse_ts_import_equals_declaration(
Expand Down
22 changes: 18 additions & 4 deletions crates/oxc_parser/src/ts/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,16 +151,30 @@ impl<'a> ParserImpl<'a> {
pub(crate) fn parse_ts_type_parameters(
&mut self,
) -> Option<Box<'a, TSTypeParameterDeclaration<'a>>> {
self.parse_ts_type_parameters_impl().0
}

/// Parse TypeScript type parameters and return whether there was a trailing comma.
/// Used for arrow functions to check for TS7060 (JSX-like type parameters in .mts/.cts).
pub(crate) fn parse_ts_type_parameters_with_trailing_comma(
&mut self,
) -> (Option<Box<'a, TSTypeParameterDeclaration<'a>>>, bool) {
self.parse_ts_type_parameters_impl()
}

fn parse_ts_type_parameters_impl(
&mut self,
) -> (Option<Box<'a, TSTypeParameterDeclaration<'a>>>, bool) {
if !self.is_ts {
return None;
return (None, false);
}
if !self.at(Kind::LAngle) {
return None;
return (None, false);
}
let span = self.start_span();
let opening_span = self.cur_token().span();
self.expect(Kind::LAngle);
let (params, _) = self.parse_delimited_list(
let (params, trailing_comma) = self.parse_delimited_list(
Kind::RAngle,
Kind::Comma,
opening_span,
Expand All @@ -171,7 +185,7 @@ impl<'a> ParserImpl<'a> {
if params.is_empty() {
self.error(diagnostics::ts_empty_type_parameter_list(span));
}
Some(self.ast.alloc_ts_type_parameter_declaration(span, params))
(Some(self.ast.alloc_ts_type_parameter_declaration(span, params)), trailing_comma.is_some())
}

pub(crate) fn parse_ts_implements_clause(&mut self) -> Vec<'a, TSClassImplements<'a>> {
Expand Down
28 changes: 25 additions & 3 deletions tasks/coverage/snapshots/parser_typescript.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ commit: 95e3aaa9
parser_typescript Summary:
AST Parsed : 9842/9843 (99.99%)
Positive Passed: 9838/9843 (99.95%)
Negative Passed: 1514/2557 (59.21%)
Negative Passed: 1515/2557 (59.25%)
Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/FunctionDeclaration3.ts

Expect Syntax Error: tasks/coverage/typescript/tests/cases/compiler/FunctionDeclaration4.ts
Expand Down Expand Up @@ -1690,8 +1690,6 @@ Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/node/node

Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/node/nodeModulesExportsBlocksTypesVersions.ts

Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/node/nodeModulesForbidenSyntax.ts

Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/node/nodeModulesGeneratedNameCollisions.ts

Expect Syntax Error: tasks/coverage/typescript/tests/cases/conformance/node/nodeModulesImportAssertions.ts
Expand Down Expand Up @@ -21115,6 +21113,30 @@ Expect to Parse: tasks/coverage/typescript/tests/cases/conformance/statements/Va
╰────
help: TypeScript transforms 'import ... =' to 'const ... ='

× TS(7060): This syntax is reserved in files with the .mts or .cts extension. Add a trailing comma or explicit constraint.
╭─[typescript/tests/cases/conformance/node/nodeModulesForbidenSyntax.ts:2:12]
1 │ // cjs format file
2 │ const x = <T>() => <T><any>(void 0);
· ─
3 │ export {x};
╰────

× TS(7059): This syntax is reserved in files with the .mts or .cts extension. Use an `as` expression instead.
╭─[typescript/tests/cases/conformance/node/nodeModulesForbidenSyntax.ts:2:23]
1 │ // cjs format file
2 │ const x = <T>() => <T><any>(void 0);
· ─────────────
3 │ export {x};
╰────

× TS(7059): This syntax is reserved in files with the .mts or .cts extension. Use an `as` expression instead.
╭─[typescript/tests/cases/conformance/node/nodeModulesForbidenSyntax.ts:2:20]
1 │ // cjs format file
2 │ const x = <T>() => <T><any>(void 0);
· ────────────────
3 │ export {x};
╰────

× Expected 'with' in import type options
╭─[typescript/tests/cases/conformance/node/nodeModulesImportAttributesTypeModeDeclarationEmitErrors.ts:3:22]
2 │ export type LocalInterface =
Expand Down
4 changes: 2 additions & 2 deletions tasks/transform_conformance/snapshots/babel.snap.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
commit: 92c052dc

Passed: 699/1164
Passed: 695/1160

# All Passed:
* babel-plugin-transform-logical-assignment-operators
Expand Down Expand Up @@ -1311,7 +1311,7 @@ x Output mismatch
x Output mismatch


# babel-preset-typescript (11/16)
# babel-preset-typescript (7/12)
* node-extensions/import-in-cts/input.cts
x Output mismatch

Expand Down
Loading