Skip to content
This repository was archived by the owner on Aug 31, 2023. It is now read-only.

Commit

Permalink
fix(rome_js_semantic): include binding for type parameters (#3803)
Browse files Browse the repository at this point in the history
  • Loading branch information
95th authored Nov 21, 2022
1 parent 861eb07 commit 9c2e949
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// valid
export type EventHandler<T extends string> = `on${T}`
export type EventHandlerDefault<T extends string = 'click'> = `on${T}`

export type NestedContext<S extends NestedContext<''>> = '' | `(${S})`
export type NestedContextDefault<S extends NestedContextDefault = ''> = '' | `(${S})`

export type Whatever<S extends number> = `Hello ${S}`
export type WhateverDefault<S extends number = 2> = `Hello ${S}`

// Invalid
export type Invalid<S extends number> = `Hello ${T}`
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
source: crates/rome_js_analyze/tests/spec_tests.rs
expression: noUndeclaredVariables.ts
---
# Input
```js
// valid
export type EventHandler<T extends string> = `on${T}`
export type EventHandlerDefault<T extends string = 'click'> = `on${T}`

export type NestedContext<S extends NestedContext<''>> = '' | `(${S})`
export type NestedContextDefault<S extends NestedContextDefault = ''> = '' | `(${S})`

export type Whatever<S extends number> = `Hello ${S}`
export type WhateverDefault<S extends number = 2> = `Hello ${S}`

// Invalid
export type Invalid<S extends number> = `Hello ${T}`
```

# Diagnostics
```
noUndeclaredVariables.ts:12:50 lint/correctness/noUndeclaredVariables ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
! The T variable is undeclared
11 │ // Invalid
> 12 │ export type Invalid<S extends number> = `Hello ${T}`
│ ^
```


14 changes: 10 additions & 4 deletions crates/rome_js_semantic/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rome_js_syntax::{
JsCallExpression, JsForVariableDeclaration, JsIdentifierAssignment, JsIdentifierBinding,
JsLanguage, JsParenthesizedExpression, JsReferenceIdentifier, JsSyntaxKind, JsSyntaxNode,
JsSyntaxToken, JsVariableDeclaration, JsVariableDeclarator, JsVariableDeclaratorList,
JsxReferenceIdentifier, TextRange, TextSize, TsIdentifierBinding,
JsxReferenceIdentifier, TextRange, TextSize, TsIdentifierBinding, TsTypeParameter,
};
use rome_rowan::{syntax::Preorder, AstNode, SyntaxNodeCast, SyntaxNodeOptionExt, SyntaxTokenText};

Expand Down Expand Up @@ -245,7 +245,7 @@ impl SemanticEventExtractor {
use rome_js_syntax::JsSyntaxKind::*;

match node.kind() {
JS_IDENTIFIER_BINDING | TS_IDENTIFIER_BINDING => {
JS_IDENTIFIER_BINDING | TS_IDENTIFIER_BINDING | TS_TYPE_PARAMETER => {
self.enter_identifier_binding(node);
}
JS_REFERENCE_IDENTIFIER | JSX_REFERENCE_IDENTIFIER => {
Expand Down Expand Up @@ -322,8 +322,8 @@ impl SemanticEventExtractor {
use JsSyntaxKind::*;
debug_assert!(matches!(
node.kind(),
JS_IDENTIFIER_BINDING | TS_IDENTIFIER_BINDING
), "specified node is not a identifier binding (JS_IDENTIFIER_BINDING, TS_IDENTIFIER_BINDING)");
JS_IDENTIFIER_BINDING | TS_IDENTIFIER_BINDING | TS_TYPE_PARAMETER
), "specified node is not a identifier binding (JS_IDENTIFIER_BINDING, TS_IDENTIFIER_BINDING, TS_TYPE_PARAMETER)");

let (name_token, is_var) = match node.kind() {
JS_IDENTIFIER_BINDING => {
Expand All @@ -338,6 +338,12 @@ impl SemanticEventExtractor {
let is_var = Self::is_var(&binding);
(name_token, is_var)
}
TS_TYPE_PARAMETER => {
let binding = node.clone().cast::<TsTypeParameter>()?;
let name_token = binding.name().ok()?.ident_token().ok()?;
let is_var = Self::is_var(&binding);
(name_token, is_var)
}
_ => return None,
};

Expand Down
4 changes: 0 additions & 4 deletions crates/rome_js_semantic/src/tests/assertions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -669,10 +669,6 @@ impl SemanticAssertions {
// where we expect
let e = events.iter().find(|event| match event {
SemanticEvent::ScopeEnded { started_at, .. } => {
println!(
"started_at: {:?} scope_start_assertions_range: {:?}",
started_at, scope_start_assertions_range
);
*started_at == scope_start_assertions_range.start()
}
_ => false,
Expand Down
15 changes: 15 additions & 0 deletions crates/rome_js_semantic/src/tests/scopes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,21 @@ assert_semantics! {
ok_scope_class_setter, ";class A { set/*START A*/ name(v) {}/*END A*/ }",
}

// Type parameters
assert_semantics! {
ok_type_parameter, "export type /*START A*/ EventHandler<Event /*# Event */ /*@ A */ extends string> = `on${ Event /*READ Event */ }` /*END A*/",
ok_type_parameter_with_default, "export type /*START A */ EventHandler<Event /*# Event */ /*@ A */ extends string = 'click'> = `on${ Event /*READ Event */ }` /*END A*/",
ok_type_parameter_multiple_declaration, "
export type /*START ScopeA */ EventHandler<Event /*# EventA */ /*@ ScopeA */ extends string> = `on${ Event /*READ EventA */ }`; /*END ScopeA */
export type /*START ScopeB */ EventHandlerDefault<Event /*# EventB */ /*@ ScopeB */ extends string = 'click'> = `on${ Event /*READ EventB */ }`; /*END ScopeB */
",
ok_type_parameter_interface, "
export interface /*START A*/ EventHandler<Event /*# Event */ /*@ A */ extends string> {
[`on${ Event /*READ Event */ }`]: (event: Event /*READ Event */, data: unknown) => void;
} /*END A*/
",
}

// Others
assert_semantics! {
ok_scope_global, "/*START GLOBAL*//*END GLOBAL*/",
Expand Down

0 comments on commit 9c2e949

Please sign in to comment.