From b346a9ad6debc3016dd288f3c2c9e595b47a0a37 Mon Sep 17 00:00:00 2001 From: u9g Date: Wed, 16 Aug 2023 00:56:43 -0400 Subject: [PATCH] feat(query): New types and new fields for existing types (#746) ```diff + Argument.value + Argument implements HasSpan + ArgumentAST - FnCall.arguments + FnCall.argument - FnCallAST.arguments + FnCallAST.argument + interface Function + Function.is_async + Function.is_generator + Function.parameter + Function implements Expression + Function implements HasSpan + Parameter + Parameter.is_readonly + Parameter.assignment + Parameter.type_annotation + Parameter implements HasSpan + ParameterAST + ArrowFunction implements Function + ArrowFunction implements Expression + ArrowFunctionAST implements Function + ArrowFunctionAST implements Expression + FnDeclaration implements Function + FnDeclaration implements Expression + FnDeclarationAST implements Function + FnDeclarationAST implements Expression ``` --- crates/oxc_query/src/adapter.rs | 33 ++++- crates/oxc_query/src/edges.rs | 203 ++++++++++++++++++++++++++-- crates/oxc_query/src/properties.rs | 66 +++++++++ crates/oxc_query/src/schema.graphql | 122 ++++++++++++++++- crates/oxc_query/src/vertex.rs | 89 +++++++++++- 5 files changed, 487 insertions(+), 26 deletions(-) diff --git a/crates/oxc_query/src/adapter.rs b/crates/oxc_query/src/adapter.rs index 1d3b32b7f..759ffebe0 100644 --- a/crates/oxc_query/src/adapter.rs +++ b/crates/oxc_query/src/adapter.rs @@ -71,6 +71,13 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> { return resolve_property_with(contexts, |v| v.typename().into()); } match type_name.as_ref() { + "ArrowFunctionAST" | "ArrowFunction" => { + super::properties::resolve_arrow_function_property( + contexts, + property_name.as_ref(), + resolve_info, + ) + } "AssignmentType" => super::properties::resolve_assignment_type_property( contexts, property_name.as_ref(), @@ -118,6 +125,11 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> { property_name.as_ref(), resolve_info, ), + "Function" => super::properties::resolve_function_property( + contexts, + property_name.as_ref(), + resolve_info, + ), "ImportAST" | "Import" => super::properties::resolve_import_property( contexts, property_name.as_ref(), @@ -169,6 +181,11 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> { resolve_info, ) } + "ParameterAST" | "Parameter" => super::properties::resolve_parameter_property( + contexts, + property_name.as_ref(), + resolve_info, + ), "PathPart" => super::properties::resolve_path_part_property( contexts, property_name.as_ref(), @@ -228,11 +245,12 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> { resolve_info, self, ), - "Argument" => super::edges::resolve_argument_edge( + "ArgumentAST" | "Argument" => super::edges::resolve_argument_edge( contexts, edge_name.as_ref(), parameters, resolve_info, + self, ), "AssignmentType" => super::edges::resolve_assignment_type_edge( contexts, @@ -278,6 +296,12 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> { parameters, resolve_info, ), + "Function" => super::edges::resolve_function_edge( + contexts, + edge_name.as_ref(), + parameters, + resolve_info, + ), "FunctionBodyAST" | "FunctionBody" => super::edges::resolve_function_body_edge( contexts, edge_name.as_ref(), @@ -438,6 +462,13 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> { resolve_info, self, ), + "ParameterAST" | "Parameter" => super::edges::resolve_parameter_edge( + contexts, + edge_name.as_ref(), + parameters, + resolve_info, + self, + ), "ReassignmentAST" | "Reassignment" => super::edges::resolve_reassignment_edge( contexts, edge_name.as_ref(), diff --git a/crates/oxc_query/src/edges.rs b/crates/oxc_query/src/edges.rs index a67242fa2..f420ad196 100644 --- a/crates/oxc_query/src/edges.rs +++ b/crates/oxc_query/src/edges.rs @@ -15,6 +15,8 @@ pub(super) fn resolve_arrow_function_edge<'a, 'b: 'a>( ) -> ContextOutcomeIterator<'a, Vertex<'b>, VertexIterator<'a, Vertex<'b>>> { match edge_name { "span" => arrow_function::span(contexts, resolve_info), + "parameter" => arrow_function::parameter(contexts, resolve_info), + "strip_parens" => strip_parens(contexts), "ancestor" => ancestors(contexts, adapter), "parent" => parents(contexts, adapter), _ => { @@ -27,11 +29,19 @@ pub(super) fn resolve_arrow_function_edge<'a, 'b: 'a>( mod arrow_function { use trustfall::provider::{ - ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, VertexIterator, + resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, + VertexIterator, }; use super::super::vertex::Vertex; + pub(super) fn parameter<'a, 'b: 'a>( + contexts: ContextIterator<'a, Vertex<'b>>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex<'b>, VertexIterator<'a, Vertex<'b>>> { + resolve_neighbors_with(contexts, |v| v.function_parameter()) + } + pub(super) fn span<'a, 'b: 'a>( contexts: ContextIterator<'a, Vertex<'b>>, _resolve_info: &ResolveEdgeInfo, @@ -44,9 +54,13 @@ pub(super) fn resolve_argument_edge<'a, 'b: 'a>( edge_name: &str, _parameters: &EdgeParameters, resolve_info: &ResolveEdgeInfo, + adapter: &'a Adapter<'b>, ) -> ContextOutcomeIterator<'a, Vertex<'b>, VertexIterator<'a, Vertex<'b>>> { match edge_name { "span" => argument::span(contexts, resolve_info), + "value" => argument::value(contexts, resolve_info), + "ancestor" => ancestors(contexts, adapter), + "parent" => parents(contexts, adapter), _ => { unreachable!("attempted to resolve unexpected edge '{edge_name}' on type 'Argument'") } @@ -54,12 +68,34 @@ pub(super) fn resolve_argument_edge<'a, 'b: 'a>( } mod argument { + use oxc_ast::ast::Argument; use trustfall::provider::{ - ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, VertexIterator, + resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, + VertexIterator, }; use super::super::vertex::Vertex; + pub(super) fn value<'a, 'b: 'a>( + contexts: ContextIterator<'a, Vertex<'b>>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex<'b>, VertexIterator<'a, Vertex<'b>>> { + resolve_neighbors_with(contexts, |v| { + let expr = match v + .as_argument() + .unwrap_or_else(|| { + panic!("expected to have an argument vertex, instead have: {v:#?}") + }) + .argument + { + Argument::SpreadElement(spread) => &spread.argument, + Argument::Expression(expr) => expr, + }; + + Box::new(std::iter::once(expr.into())) + }) + } + pub(super) fn span<'a, 'b: 'a>( contexts: ContextIterator<'a, Vertex<'b>>, _resolve_info: &ResolveEdgeInfo, @@ -573,6 +609,45 @@ mod expression { } } +pub(super) fn resolve_function_edge<'a, 'b: 'a>( + contexts: ContextIterator<'a, Vertex<'b>>, + edge_name: &str, + _parameters: &EdgeParameters, + resolve_info: &ResolveEdgeInfo, +) -> ContextOutcomeIterator<'a, Vertex<'b>, VertexIterator<'a, Vertex<'b>>> { + match edge_name { + "parameter" => function::parameter(contexts, resolve_info), + "span" => function::span(contexts, resolve_info), + "strip_parens" => strip_parens(contexts), + _ => { + unreachable!("attempted to resolve unexpected edge '{edge_name}' on type 'Function'") + } + } +} + +mod function { + use trustfall::provider::{ + resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, + VertexIterator, + }; + + use super::super::vertex::Vertex; + + pub(super) fn parameter<'a, 'b: 'a>( + contexts: ContextIterator<'a, Vertex<'b>>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex<'b>, VertexIterator<'a, Vertex<'b>>> { + resolve_neighbors_with(contexts, |v| v.function_parameter()) + } + + pub(super) fn span<'a, 'b: 'a>( + contexts: ContextIterator<'a, Vertex<'b>>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex<'b>, VertexIterator<'a, Vertex<'b>>> { + super::get_span(contexts) + } +} + pub(super) fn resolve_function_body_edge<'a, 'b: 'a>( contexts: ContextIterator<'a, Vertex<'b>>, edge_name: &str, @@ -636,6 +711,8 @@ pub(super) fn resolve_fn_declaration_edge<'a, 'b: 'a>( ) -> ContextOutcomeIterator<'a, Vertex<'b>, VertexIterator<'a, Vertex<'b>>> { match edge_name { "span" => fn_declaration::span(contexts, resolve_info), + "parameter" => fn_declaration::parameter(contexts, resolve_info), + "strip_parens" => strip_parens(contexts), "ancestor" => ancestors(contexts, adapter), "parent" => parents(contexts, adapter), _ => { @@ -648,11 +725,19 @@ pub(super) fn resolve_fn_declaration_edge<'a, 'b: 'a>( mod fn_declaration { use trustfall::provider::{ - ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, VertexIterator, + resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, + VertexIterator, }; use super::super::vertex::Vertex; + pub(super) fn parameter<'a, 'b: 'a>( + contexts: ContextIterator<'a, Vertex<'b>>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex<'b>, VertexIterator<'a, Vertex<'b>>> { + resolve_neighbors_with(contexts, |v| v.function_parameter()) + } + pub(super) fn span<'a, 'b: 'a>( contexts: ContextIterator<'a, Vertex<'b>>, _resolve_info: &ResolveEdgeInfo, @@ -671,6 +756,7 @@ pub(super) fn resolve_file_edge<'a, 'b: 'a>( match edge_name { "ast_node" => file::ast_node(contexts, resolve_info, adapter), "class" => file::class(contexts, resolve_info, adapter), + "function" => file::function(contexts, resolve_info, adapter), "import" => file::import(contexts, resolve_info, adapter), "interface" => file::interface(contexts, resolve_info, adapter), "jsx_element" => file::jsx_element(contexts, resolve_info, adapter), @@ -717,6 +803,23 @@ mod file { }) } + pub(super) fn function<'a, 'b: 'a>( + contexts: ContextIterator<'a, Vertex<'b>>, + _resolve_info: &ResolveEdgeInfo, + adapter: &'a Adapter<'b>, + ) -> ContextOutcomeIterator<'a, Vertex<'b>, VertexIterator<'a, Vertex<'b>>> { + resolve_neighbors_with(contexts, |_| { + Box::new( + adapter + .semantic + .nodes() + .iter() + .map(|node| (*node).into()) + .filter(|x: &Vertex<'_>| x.is_arrow_function() || x.is_fn_declaration()), + ) + }) + } + pub(super) fn import<'a, 'b: 'a>( contexts: ContextIterator<'a, Vertex<'b>>, _resolve_info: &ResolveEdgeInfo, @@ -814,7 +917,7 @@ pub(super) fn resolve_fn_call_edge<'a, 'b: 'a>( match edge_name { "span" => fn_call::span(contexts, resolve_info), "callee" => fn_call::callee(contexts, resolve_info), - "arguments" => fn_call::arguments(contexts, resolve_info), + "argument" => fn_call::argument(contexts, resolve_info), "ancestor" => ancestors(contexts, adapter), "parent" => parents(contexts, adapter), "strip_parens" => strip_parens(contexts), @@ -825,13 +928,13 @@ pub(super) fn resolve_fn_call_edge<'a, 'b: 'a>( } mod fn_call { - use oxc_ast::ast::Argument; - use oxc_span::GetSpan; use trustfall::provider::{ resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, VertexIterator, }; + use crate::vertex::ArgumentVertex; + use super::super::vertex::Vertex; pub(super) fn callee<'a, 'b: 'a>( @@ -851,7 +954,7 @@ mod fn_call { }) } - pub(super) fn arguments<'a, 'b: 'a>( + pub(super) fn argument<'a, 'b: 'a>( contexts: ContextIterator<'a, Vertex<'b>>, _resolve_info: &ResolveEdgeInfo, ) -> ContextOutcomeIterator<'a, Vertex<'b>, VertexIterator<'a, Vertex<'b>>> { @@ -864,11 +967,8 @@ mod fn_call { .call_expression .arguments .iter() - .map(|x| { - Vertex::Argument(match x { - Argument::SpreadElement(spread) => spread.span, - Argument::Expression(expr) => expr.span(), - }) + .map(|argument| { + Vertex::Argument(ArgumentVertex { ast_node: None, argument }.into()) }), ) }) @@ -1990,6 +2090,85 @@ mod path_part { } } +pub(super) fn resolve_parameter_edge<'a, 'b: 'a>( + contexts: ContextIterator<'a, Vertex<'b>>, + edge_name: &str, + _parameters: &EdgeParameters, + resolve_info: &ResolveEdgeInfo, + adapter: &'a Adapter<'b>, +) -> ContextOutcomeIterator<'a, Vertex<'b>, VertexIterator<'a, Vertex<'b>>> { + match edge_name { + "ancestor" => ancestors(contexts, adapter), + "parent" => parents(contexts, adapter), + "span" => parameter::span(contexts, resolve_info), + "assignment" => parameter::assignment(contexts, resolve_info), + "type_annotation" => parameter::type_annotation(contexts, resolve_info), + _ => { + unreachable!("attempted to resolve unexpected edge '{edge_name}' on type 'Parameter'") + } + } +} + +mod parameter { + + use trustfall::provider::{ + resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, + VertexIterator, + }; + + use crate::vertex::TypeAnnotationVertex; + + use super::{super::vertex::Vertex, get_span}; + + pub(super) fn assignment<'a, 'b: 'a>( + contexts: ContextIterator<'a, Vertex<'b>>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex<'b>, VertexIterator<'a, Vertex<'b>>> { + resolve_neighbors_with(contexts, |v| { + Box::new(std::iter::once(Vertex::AssignmentType( + &v.as_parameter() + .unwrap_or_else(|| { + panic!("expected to have a parameter vertex, instead have: {v:#?}") + }) + .parameter + .pattern + .kind, + ))) + }) + } + + pub(super) fn type_annotation<'a, 'b: 'a>( + contexts: ContextIterator<'a, Vertex<'b>>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex<'b>, VertexIterator<'a, Vertex<'b>>> { + resolve_neighbors_with(contexts, |v| { + Box::new( + v.as_parameter() + .unwrap_or_else(|| { + panic!("expected to have a parameter vertex, instead have: {v:#?}") + }) + .parameter + .pattern + .type_annotation + .as_ref() + .map(|type_annotation| { + Vertex::TypeAnnotation( + TypeAnnotationVertex { type_annotation, ast_node: None }.into(), + ) + }) + .into_iter(), + ) + }) + } + + pub(super) fn span<'a, 'b: 'a>( + contexts: ContextIterator<'a, Vertex<'b>>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex<'b>, VertexIterator<'a, Vertex<'b>>> { + get_span(contexts) + } +} + pub(super) fn resolve_reassignment_edge<'a, 'b: 'a>( contexts: ContextIterator<'a, Vertex<'b>>, edge_name: &str, diff --git a/crates/oxc_query/src/properties.rs b/crates/oxc_query/src/properties.rs index bc43d4fe0..01cdafd46 100644 --- a/crates/oxc_query/src/properties.rs +++ b/crates/oxc_query/src/properties.rs @@ -17,6 +17,25 @@ use crate::{ Adapter, }; +pub(super) fn resolve_arrow_function_property<'a, 'b: 'a>( + contexts: ContextIterator<'a, Vertex<'b>>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, Vertex<'b>, FieldValue> { + match property_name { + "is_async" => resolve_property_with(contexts, |v| v.function_is_async().into()), + "is_generator" => resolve_property_with(contexts, |v| v.function_is_generator().into()), + "as_constant_string" => resolve_property_with(contexts, |v| { + v.as_constant_string().map_or(FieldValue::Null, Into::into) + }), + _ => { + unreachable!( + "attempted to read unexpected property '{property_name}' on type 'AssignmentType'" + ) + } + } +} + pub(super) fn resolve_assignment_type_property<'a, 'b: 'a>( contexts: ContextIterator<'a, Vertex<'b>>, property_name: &str, @@ -205,6 +224,11 @@ pub(super) fn resolve_fn_declaration_property<'a, 'b: 'a>( .as_ref() .map_or_else(|| FieldValue::Null, |f| f.name.to_string().into()) }), + "is_async" => resolve_property_with(contexts, |v| v.function_is_async().into()), + "is_generator" => resolve_property_with(contexts, |v| v.function_is_generator().into()), + "as_constant_string" => resolve_property_with(contexts, |v| { + v.as_constant_string().map_or(FieldValue::Null, Into::into) + }), _ => { unreachable!( "attempted to read unexpected property '{property_name}' on type 'FnDeclaration'" @@ -228,6 +252,25 @@ pub(super) fn resolve_fn_call_property<'a, 'b: 'a>( } } +pub(super) fn resolve_function_property<'a, 'b: 'a>( + contexts: ContextIterator<'a, Vertex<'b>>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, Vertex<'b>, FieldValue> { + match property_name { + "is_async" => resolve_property_with(contexts, |v| v.function_is_async().into()), + "is_generator" => resolve_property_with(contexts, |v| v.function_is_generator().into()), + "as_constant_string" => resolve_property_with(contexts, |v| { + v.as_constant_string().map_or(FieldValue::Null, Into::into) + }), + _ => { + unreachable!( + "attempted to read unexpected property '{property_name}' on type 'Function'" + ) + } + } +} + pub(super) fn resolve_import_property<'a, 'b: 'a>( contexts: ContextIterator<'a, Vertex<'b>>, property_name: &str, @@ -438,6 +481,29 @@ pub(super) fn resolve_object_literal_property<'a, 'b: 'a>( } } +pub(super) fn resolve_parameter_property<'a, 'b: 'a>( + contexts: ContextIterator<'a, Vertex<'b>>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, Vertex<'b>, FieldValue> { + match property_name { + "is_readonly" => resolve_property_with(contexts, |v| { + v.as_parameter() + .unwrap_or_else(|| { + panic!("expected to have a parameter vertex, instead have: {v:#?}") + }) + .parameter + .readonly + .into() + }), + _ => { + unreachable!( + "attempted to read unexpected property '{property_name}' on type 'Parameter'" + ) + } + } +} + pub(super) fn resolve_path_part_property<'a, 'b: 'a>( contexts: ContextIterator<'a, Vertex<'b>>, property_name: &str, diff --git a/crates/oxc_query/src/schema.graphql b/crates/oxc_query/src/schema.graphql index d2632a8d6..a67429119 100644 --- a/crates/oxc_query/src/schema.graphql +++ b/crates/oxc_query/src/schema.graphql @@ -62,6 +62,8 @@ type File { import: [ImportAST!]! variable_declaration: [VariableDeclarationAST!]! + function: [Function!]! + ast_node: [ASTNode!]! } @@ -391,13 +393,24 @@ type ObjectLiteralAST implements ObjectLiteral & Expression & HasSpan & ASTNode span: Span! } -interface Argument { +interface Argument implements HasSpan { + value: Expression! + # HasSpan + span: Span! +} + +type ArgumentAST implements Argument & HasSpan & ASTNode { + value: Expression! + # ASTNode + parent: ASTNode + ancestor: [ASTNode!]! + # HasSpan span: Span! } interface FnCall implements Expression & HasSpan { callee: Expression! - arguments: [Argument!]! + argument: [Argument!]! # Expression as_constant_string: String @@ -408,7 +421,7 @@ interface FnCall implements Expression & HasSpan { type FnCallAST implements FnCall & Expression & HasSpan & ASTNode { callee: Expression! - arguments: [Argument!]! + argument: [Argument!]! # Expression as_constant_string: String @@ -481,12 +494,79 @@ type FunctionBodyAST implements HasSpan & ASTNode & FunctionBody { ancestor: [ASTNode!]! } -interface ArrowFunction implements HasSpan { +interface Function implements Expression & HasSpan { + is_async: Boolean! + is_generator: Boolean! + """ + Does not include rest parameter if it exists. + """ + parameter: [Parameter]! + + # Expression + """ + Only non-null if the string can be trivially coerced to a constant string + ie: const a = "apple"; const b = `blueberry` + """ + as_constant_string: String + strip_parens: Expression! + # HasSpan span: Span! } -type ArrowFunctionAST implements HasSpan & ArrowFunction & ASTNode { +type Parameter { + is_readonly: Boolean! + assignment: AssignmentType! + type_annotation: TypeAnnotation! + # HasSpan + span: Span! +} + +type ParameterAST implements ASTNode & HasSpan { + is_readonly: Boolean! + assignment: AssignmentType! + type_annotation: TypeAnnotation! + # HasSpan + span: Span! + # ASTNode + parent: ASTNode + ancestor: [ASTNode!]! +} + +interface ArrowFunction implements Function & HasSpan & Expression { + # Function + is_async: Boolean! + is_generator: Boolean! + """ + Does not include rest parameter if it exists. + """ + parameter: [Parameter]! + # Expression + """ + Only non-null if the string can be trivially coerced to a constant string + ie: const a = "apple"; const b = `blueberry` + """ + as_constant_string: String + strip_parens: Expression! + # HasSpan + span: Span! +} + +type ArrowFunctionAST implements Function & HasSpan & ArrowFunction & ASTNode & Expression { + # Function + is_async: Boolean! + is_generator: Boolean! + """ + Does not include rest parameter if it exists. + """ + parameter: [Parameter]! + # Expression + """ + Only non-null if the string can be trivially coerced to a constant string + ie: const a = "apple"; const b = `blueberry` + """ + as_constant_string: String + strip_parens: Expression! # HasSpan span: Span! # ASTNode @@ -497,13 +577,27 @@ type ArrowFunctionAST implements HasSpan & ArrowFunction & ASTNode { """ A function defined in the sourcecode. """ -interface FnDeclaration implements HasSpan { +interface FnDeclaration implements Function & HasSpan & Expression { """ If this function is used an an expression, the name can be omitted. ie: "const a = function() {};" """ name: String + # Function + is_async: Boolean! + is_generator: Boolean! + """ + Does not include rest parameter if it exists. + """ + parameter: [Parameter]! + # Expression + """ + Only non-null if the string can be trivially coerced to a constant string + ie: const a = "apple"; const b = `blueberry` + """ + as_constant_string: String + strip_parens: Expression! # HasSpan span: Span! } @@ -511,12 +605,26 @@ interface FnDeclaration implements HasSpan { """ A function defined in the sourcecode. """ -type FnDeclarationAST implements ASTNode & FnDeclaration & HasSpan { +type FnDeclarationAST implements Function & ASTNode & FnDeclaration & HasSpan & Expression { name: String + # Function + is_async: Boolean! + is_generator: Boolean! + """ + Does not include rest parameter if it exists. + """ + parameter: [Parameter]! # ASTNode parent: ASTNode ancestor: [ASTNode!]! + # Expression + """ + Only non-null if the string can be trivially coerced to a constant string + ie: const a = "apple"; const b = `blueberry` + """ + as_constant_string: String + strip_parens: Expression! # HasSpan span: Span! } diff --git a/crates/oxc_query/src/vertex.rs b/crates/oxc_query/src/vertex.rs index ca942f7a7..de99d0d67 100644 --- a/crates/oxc_query/src/vertex.rs +++ b/crates/oxc_query/src/vertex.rs @@ -5,7 +5,7 @@ use enum_as_inner::EnumAsInner; use oxc_ast::{ast::*, AstKind}; use oxc_semantic::{AstNode, AstNodeId}; use oxc_span::{GetSpan, Span}; -use trustfall::provider::Typename; +use trustfall::provider::{Typename, VertexIterator}; use url::Url; use crate::util::{expr_to_maybe_const_string, jsx_attribute_to_constant_string}; @@ -52,9 +52,10 @@ pub enum Vertex<'a> { FnCall(Rc>), FnDeclaration(Rc>), ArrowFunction(Rc>), - Argument(Span), + Argument(Rc>), FunctionBody(Rc>), Statement(&'a Statement<'a>), + Parameter(Rc>), } impl<'a> Vertex<'a> { @@ -95,11 +96,12 @@ impl<'a> Vertex<'a> { Self::Reassignment(data) => data.assignment_expression.span, Self::Name(data) => data.name.span, Self::FnCall(data) => data.call_expression.span, - Self::Argument(data) => *data, + Self::Argument(data) => data.argument.span(), Self::FnDeclaration(data) => data.function.span, Self::ArrowFunction(data) => data.arrow_expression.span, Self::FunctionBody(data) => data.function_body.span, Self::Statement(data) => data.span(), + Self::Parameter(data) => data.parameter.span, Self::File | Self::Url(_) | Self::PathPart(_) @@ -133,6 +135,8 @@ impl<'a> Vertex<'a> { Vertex::FnDeclaration(data) => data.ast_node.map(|x| x.id()), Vertex::ArrowFunction(data) => data.ast_node.map(|x| x.id()), Vertex::FunctionBody(data) => data.ast_node.map(|x| x.id()), + Vertex::Parameter(data) => data.ast_node.map(|x| x.id()), + Vertex::Argument(data) => data.ast_node.map(|x| x.id()), Vertex::DefaultImport(_) | Vertex::Statement(_) | Vertex::AssignmentType(_) @@ -152,7 +156,6 @@ impl<'a> Vertex<'a> { | Vertex::SpecificImport(_) | Vertex::Span(_) | Vertex::SearchParameter(_) - | Vertex::Argument(_) | Vertex::ClassProperty(_) => None, } } @@ -190,6 +193,39 @@ impl<'a> Vertex<'a> { ) -> Option { None } + + pub fn function_is_async(&self) -> bool { + match &self { + Vertex::ArrowFunction(data) => data.arrow_expression.r#async, + Vertex::FnDeclaration(data) => data.function.r#async, + _ => unreachable!( + "'function_is_async' function should only ever be called with an ArrowFunction or FnDeclaration" + ), + } + } + + pub fn function_is_generator(&self) -> bool { + match &self { + Vertex::ArrowFunction(data) => data.arrow_expression.generator, + Vertex::FnDeclaration(data) => data.function.generator, + _ => unreachable!( + "'function_is_generator' function should only ever be called with an ArrowFunction or FnDeclaration" + ), + } + } + + pub fn function_parameter(&self) -> VertexIterator<'a, Vertex<'a>> { + let parameter = match &self { + Vertex::ArrowFunction(data) => &data.arrow_expression.params.items, + Vertex::FnDeclaration(data) => &data.function.params.items, + _ => unreachable!( + "'function_parameter' function should only ever be called with an ArrowFunction or FnDeclaration" + ), + }; + Box::new(parameter.iter().map(|parameter| { + Vertex::Parameter(ParameterVertex { ast_node: None, parameter }.into()) + })) + } } impl Typename for Vertex<'_> { @@ -235,10 +271,11 @@ impl Typename for Vertex<'_> { Vertex::ObjectEntry(entry) => entry.typename(), Vertex::FnCall(fncall) => fncall.typename(), Vertex::Reassignment(reassignment) => reassignment.typename(), - Vertex::Argument(_) => "Argument", + Vertex::Argument(arg) => arg.typename(), Vertex::FnDeclaration(fndecl) => fndecl.typename(), Vertex::ArrowFunction(arrow_fn) => arrow_fn.typename(), Vertex::FunctionBody(fn_body) => fn_body.typename(), + Vertex::Parameter(param) => param.typename(), Vertex::Statement(_) => "Statement", } } @@ -319,6 +356,12 @@ impl<'a> From> for Vertex<'a> { AstKind::FunctionBody(function_body) => Vertex::FunctionBody( FunctionBodyVertex { ast_node: Some(ast_node), function_body }.into(), ), + AstKind::FormalParameter(parameter) => { + Vertex::Parameter(ParameterVertex { ast_node: Some(ast_node), parameter }.into()) + } + AstKind::Argument(argument) => { + Vertex::Argument(ArgumentVertex { ast_node: Some(ast_node), argument }.into()) + } _ => Vertex::ASTNode(ast_node), } } @@ -502,7 +545,7 @@ impl<'a> Typename for ReturnVertex<'a> { #[non_exhaustive] #[derive(Debug, Clone)] pub struct TypeAnnotationVertex<'a> { - ast_node: Option>, + pub ast_node: Option>, pub type_annotation: &'a TSTypeAnnotation<'a>, } @@ -743,3 +786,37 @@ impl<'a> Typename for FunctionBodyVertex<'a> { } } } + +#[non_exhaustive] +#[derive(Debug, Clone)] +pub struct ParameterVertex<'a> { + ast_node: Option>, + pub parameter: &'a FormalParameter<'a>, +} + +impl<'a> Typename for ParameterVertex<'a> { + fn typename(&self) -> &'static str { + if self.ast_node.is_some() { + "ParameterAST" + } else { + "Parameter" + } + } +} + +#[non_exhaustive] +#[derive(Debug, Clone)] +pub struct ArgumentVertex<'a> { + pub ast_node: Option>, + pub argument: &'a Argument<'a>, +} + +impl<'a> Typename for ArgumentVertex<'a> { + fn typename(&self) -> &'static str { + if self.ast_node.is_some() { + "ArgumentAST" + } else { + "Argument" + } + } +}