Skip to content

Commit 1ed8df2

Browse files
authored
feat(parser): parse const type parameter from TypeScript v5.0 (#416)
1 parent 1c19c2c commit 1ed8df2

File tree

12 files changed

+74
-85
lines changed

12 files changed

+74
-85
lines changed

crates/oxc_ast/src/ast/ts.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ pub struct TSTypeParameter<'a> {
418418
pub default: Option<TSType<'a>>,
419419
pub r#in: bool,
420420
pub out: bool,
421+
pub r#const: bool,
421422
}
422423

423424
#[derive(Debug, Hash)]

crates/oxc_ast/src/ast_builder.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1056,8 +1056,9 @@ impl<'a> AstBuilder<'a> {
10561056
default: Option<TSType<'a>>,
10571057
r#in: bool,
10581058
out: bool,
1059+
r#const: bool,
10591060
) -> Box<'a, TSTypeParameter<'a>> {
1060-
self.alloc(TSTypeParameter { span, name, constraint, default, r#in, out })
1061+
self.alloc(TSTypeParameter { span, name, constraint, default, r#in, out, r#const })
10611062
}
10621063

10631064
pub fn ts_type_parameters(

crates/oxc_parser/src/js/function.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,14 @@ impl<'a> Parser<'a> {
400400
_ => IsParenthesizedArrowFunction::False,
401401
},
402402
Kind::LAngle => {
403-
if !self.nth_kind(offset + 1).is_identifier() {
403+
let kind = self.nth_kind(offset + 1);
404+
405+
// `<const` for const type parameter from TypeScript 5.0
406+
if kind == Kind::Const {
407+
return IsParenthesizedArrowFunction::Maybe;
408+
}
409+
410+
if !kind.is_identifier() {
404411
return IsParenthesizedArrowFunction::False;
405412
}
406413

crates/oxc_parser/src/ts/types.rs

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -152,28 +152,44 @@ impl<'a> Parser<'a> {
152152
pub(crate) fn parse_ts_type_parameter(&mut self) -> Result<Box<'a, TSTypeParameter<'a>>> {
153153
let span = self.start_span();
154154

155-
let r#in = if self.at(Kind::In) && self.peek_kind().is_identifier_name() {
156-
self.bump_any();
157-
true
158-
} else {
159-
false
160-
};
161-
let out = if self.at(Kind::Out) && self.peek_kind().is_identifier_name() {
162-
self.bump_any();
163-
true
164-
} else {
165-
false
166-
};
155+
let mut r#in = false;
156+
let mut out = false;
157+
let mut r#const = false;
167158

168-
if self.at(Kind::In) && self.peek_kind().is_identifier_name() {
169-
// TODO error
159+
match self.cur_kind() {
160+
Kind::In if self.peek_kind().is_identifier_name() => {
161+
self.bump_any();
162+
r#in = true;
163+
if self.at(Kind::Out) && self.peek_kind().is_identifier_name() {
164+
// `<in out T>`
165+
self.bump_any();
166+
out = true;
167+
}
168+
}
169+
Kind::Out if self.peek_kind().is_identifier_name() => {
170+
self.bump_any();
171+
out = true;
172+
}
173+
Kind::Const if self.peek_kind().is_identifier_name() => {
174+
self.bump_any();
175+
r#const = true;
176+
}
177+
_ => {}
170178
}
171179

172180
let name = self.parse_binding_identifier()?;
173181
let constraint = self.parse_ts_type_constraint()?;
174182
let default = self.parse_ts_default_type()?;
175183

176-
Ok(self.ast.ts_type_parameter(self.end_span(span), name, constraint, default, r#in, out))
184+
Ok(self.ast.ts_type_parameter(
185+
self.end_span(span),
186+
name,
187+
constraint,
188+
default,
189+
r#in,
190+
out,
191+
r#const,
192+
))
177193
}
178194

179195
fn parse_ts_type_constraint(&mut self) -> Result<Option<TSType<'a>>> {
@@ -617,6 +633,7 @@ impl<'a> Parser<'a> {
617633
None,
618634
false,
619635
false,
636+
false,
620637
);
621638

622639
let name_type = if self.eat(Kind::As) { Some(self.parse_ts_type()?) } else { None };
@@ -813,6 +830,7 @@ impl<'a> Parser<'a> {
813830
None,
814831
false,
815832
false,
833+
false,
816834
);
817835

818836
Ok(self.ast.ts_infer_type(self.end_span(span), type_parameter))

tasks/coverage/babel

Submodule babel updated 296 files
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
formatter_test262 Summary:
2-
AST Parsed : 44745/44745 (100.00%)
3-
Positive Passed: 44745/44745 (100.00%)
2+
AST Parsed : 44738/44738 (100.00%)
3+
Positive Passed: 44738/44738 (100.00%)
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
minifier_test262 Summary:
2-
AST Parsed : 44745/44745 (100.00%)
3-
Positive Passed: 44745/44745 (100.00%)
2+
AST Parsed : 44738/44738 (100.00%)
3+
Positive Passed: 44738/44738 (100.00%)

tasks/coverage/parser_babel.snap

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
parser_babel Summary:
22
AST Parsed : 2072/2078 (99.71%)
33
Positive Passed: 2069/2078 (99.57%)
4-
Negative Passed: 1332/1507 (88.39%)
4+
Negative Passed: 1330/1507 (88.25%)
55
Expect Syntax Error: "annex-b/disabled/1.1-html-comments-close/input.js"
66
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-if-body/input.js"
77
Expect Syntax Error: "annex-b/disabled/3.1-sloppy-labeled-functions-multiple-labels/input.js"
@@ -161,6 +161,8 @@ Expect Syntax Error: "typescript/type-arguments/empty-type-ref/input.ts"
161161
Expect Syntax Error: "typescript/type-arguments/instantiation-expression-property-access/input.ts"
162162
Expect Syntax Error: "typescript/type-only-import-export-specifiers/export-invalid-type-in-type/input.ts"
163163
Expect Syntax Error: "typescript/type-only-import-export-specifiers/import-invalid-type-in-type/input.ts"
164+
Expect Syntax Error: "typescript/types/const-type-parameters-invalid-babel-7/input.ts"
165+
Expect Syntax Error: "typescript/types/const-type-parameters-invalid/input.ts"
164166
Expect Syntax Error: "typescript/types/import-type-declaration-error/input.ts"
165167
Expect Syntax Error: "typescript/types/import-type-dynamic-errors/input.ts"
166168
Expect Syntax Error: "typescript/types/intrinsic-keyword-error/input.ts"
@@ -250,19 +252,21 @@ Expect to Parse: "typescript/regression/nested-extends-in-arrow-type-param/input
250252
251253
Expect to Parse: "typescript/types/const-type-parameters-babel-7/input.ts"
252254
× Unexpected token
253-
╭─[typescript/types/const-type-parameters-babel-7/input.ts:1:1]
254-
1function a<const T>() {}
255-
· ─────
256-
2function b<const T extends U>() {}
257-
╰────
255+
╭─[typescript/types/const-type-parameters-babel-7/input.ts:13:1]
256+
13class C<T, const U> {}
257+
14class D<in const T> {}
258+
· ─────
259+
15class E<const in T> {}
260+
╰────
258261
259262
Expect to Parse: "typescript/types/const-type-parameters/input.ts"
260263
× Unexpected token
261-
╭─[typescript/types/const-type-parameters/input.ts:1:1]
262-
1function a<const T>() {}
263-
· ─────
264-
2function b<const T extends U>() {}
265-
╰────
264+
╭─[typescript/types/const-type-parameters/input.ts:13:1]
265+
13class C<T, const U> {}
266+
14class D<in const T> {}
267+
· ─────
268+
15class E<const in T> {}
269+
╰────
266270
267271
× Identifier `f` has already been declared
268272
╭─[annex-b/disabled/3.4-var-redeclaration-catch-binding/input.js:1:1]
@@ -10123,18 +10127,6 @@ Expect to Parse: "typescript/types/const-type-parameters/input.ts"
1012310127
1 │ type F = ({
1012410128
╰────
1012510129
10126-
× Unexpected token
10127-
╭─[typescript/types/const-type-parameters-invalid-babel-7/input.ts:1:1]
10128-
1 │ type T<const U> = {};
10129-
· ─────
10130-
╰────
10131-
10132-
× Unexpected token
10133-
╭─[typescript/types/const-type-parameters-invalid/input.ts:1:1]
10134-
1 │ type T<const U> = {};
10135-
· ─────
10136-
╰────
10137-
1013810130
× Keywords cannot contain escape characters
1013910131
╭─[typescript/types/import-type-escaped-error/input.ts:1:1]
1014010132
1 │ import typ\u{65} typescript from "typescript";

tasks/coverage/parser_test262.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
parser_test262 Summary:
2-
AST Parsed : 44226/44226 (100.00%)
3-
Positive Passed: 44226/44226 (100.00%)
2+
AST Parsed : 44219/44219 (100.00%)
3+
Positive Passed: 44219/44219 (100.00%)
44
Negative Passed: 3919/3947 (99.29%)
55
Expect Syntax Error: "built-ins/RegExp/prototype/unicodeSets/breaking-change-from-u-to-v-01.js"
66
Expect Syntax Error: "built-ins/RegExp/prototype/unicodeSets/breaking-change-from-u-to-v-02.js"

tasks/coverage/parser_typescript.snap

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
parser_typescript Summary:
2-
AST Parsed : 5065/5069 (99.92%)
3-
Positive Passed: 5056/5069 (99.74%)
4-
Negative Passed: 989/4751 (20.82%)
2+
AST Parsed : 5068/5071 (99.94%)
3+
Positive Passed: 5059/5071 (99.76%)
4+
Negative Passed: 986/4751 (20.75%)
55
Expect Syntax Error: "compiler/ClassDeclaration10.ts"
66
Expect Syntax Error: "compiler/ClassDeclaration11.ts"
77
Expect Syntax Error: "compiler/ClassDeclaration13.ts"
@@ -79,6 +79,7 @@ Expect Syntax Error: "compiler/argumentsPropertyNameInJsMode1.ts"
7979
Expect Syntax Error: "compiler/argumentsReferenceInConstructor4_Js.ts"
8080
Expect Syntax Error: "compiler/argumentsReferenceInMethod4_Js.ts"
8181
Expect Syntax Error: "compiler/argumentsReferenceInObjectLiteral_Js.ts"
82+
Expect Syntax Error: "compiler/argumentsSpreadRestIterables.tsx"
8283
Expect Syntax Error: "compiler/arithAssignTyping.ts"
8384
Expect Syntax Error: "compiler/arithmeticOnInvalidTypes.ts"
8485
Expect Syntax Error: "compiler/arithmeticOnInvalidTypes2.ts"
@@ -1567,6 +1568,7 @@ Expect Syntax Error: "compiler/strictNullEmptyDestructuring.ts"
15671568
Expect Syntax Error: "compiler/strictNullNotNullIndexTypeNoLib.ts"
15681569
Expect Syntax Error: "compiler/strictOptionalProperties1.ts"
15691570
Expect Syntax Error: "compiler/strictOptionalProperties3.ts"
1571+
Expect Syntax Error: "compiler/strictSubtypeAndNarrowing.ts"
15701572
Expect Syntax Error: "compiler/stringIndexerAndConstructor.ts"
15711573
Expect Syntax Error: "compiler/stringIndexerAndConstructor1.ts"
15721574
Expect Syntax Error: "compiler/stringIndexerAssignments1.ts"
@@ -3617,6 +3619,7 @@ Expect Syntax Error: "conformance/types/typeParameters/typeParameterAsBaseType.t
36173619
Expect Syntax Error: "conformance/types/typeParameters/typeParameterLists/propertyAccessOnTypeParameterWithConstraints4.ts"
36183620
Expect Syntax Error: "conformance/types/typeParameters/typeParameterLists/propertyAccessOnTypeParameterWithConstraints5.ts"
36193621
Expect Syntax Error: "conformance/types/typeParameters/typeParameterLists/staticMembersUsingClassTypeParameter.ts"
3622+
Expect Syntax Error: "conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts"
36203623
Expect Syntax Error: "conformance/types/typeParameters/typeParameterLists/typeParameterDirectlyConstrainedToItself.ts"
36213624
Expect Syntax Error: "conformance/types/typeParameters/typeParameterLists/typeParameterIndirectlyConstrainedToItself.ts"
36223625
Expect Syntax Error: "conformance/types/typeParameters/typeParameterLists/typesWithDuplicateTypeParameters.ts"
@@ -3798,15 +3801,6 @@ Expect to Parse: "compiler/emitBundleWithShebangAndPrologueDirectives1.ts"
37983801
7 │ "use strict"
37993802
╰────
38003803

3801-
Expect to Parse: "compiler/spreadsAndContextualTupleTypes.ts"
3802-
× Unexpected token
3803-
╭─[compiler/spreadsAndContextualTupleTypes.ts:26:1]
3804-
26 │
3805-
27 │ declare function foo<const T>(path: T): T;
3806-
· ─────
3807-
28 │
3808-
╰────
3809-
38103804
Expect to Parse: "compiler/withStatementInternalComments.ts"
38113805
× 'with' statements are not allowed
38123806
╭─[compiler/withStatementInternalComments.ts:1:1]
@@ -4075,14 +4069,6 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
40754069
· ╰── `:` expected
40764070
╰────
40774071

4078-
× Unexpected token
4079-
╭─[compiler/argumentsSpreadRestIterables.tsx:10:1]
4080-
10 │
4081-
11 │ declare function fn1<const T extends readonly unknown[]>(...args: T): T;
4082-
· ─────
4083-
12 │ const res1 = fn1(..."hello");
4084-
╰────
4085-
40864072
× 'arguments' is not allowed in class field initializer
40874073
╭─[compiler/argumentsUsedInClassFieldInitializerOrStaticInitializationBlock.ts:2:1]
40884074
2 │ return class T {
@@ -8568,14 +8554,6 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
85688554
· ──────
85698555
╰────
85708556

8571-
× Unexpected token
8572-
╭─[compiler/strictSubtypeAndNarrowing.ts:187:1]
8573-
187 │ ObjT extends object,
8574-
188 │ const DeepPathT extends ReadonlyArray<number | string>,
8575-
· ─────
8576-
189 │ ValueT,
8577-
╰────
8578-
85798557
× Unterminated string
85808558
╭─[compiler/stringLiteralsErrors.ts:1:1]
85818559
1 │ // Srtings missing line terminator
@@ -19046,14 +19024,6 @@ Expect to Parse: "conformance/salsa/plainJSRedeclare3.ts"
1904619024
22 │ const a9 = (f<number>)<number>; // Error, no applicable signatures
1904719025
╰────
1904819026

19049-
× Unexpected token
19050-
╭─[conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts:2:1]
19051-
2 │
19052-
3 │ declare function f1<const T>(x: T): T;
19053-
· ─────
19054-
4 │
19055-
╰────
19056-
1905719027
× Expected `,` but found `Identifier`
1905819028
╭─[conformance/types/typeParameters/typeParameterLists/varianceAnnotations.ts:97:1]
1905919029
97 │

0 commit comments

Comments
 (0)