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

fix(rome_js_semantic): include binding for type parameters #3803

Merged
merged 2 commits into from
Nov 21, 2022
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
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