From 61bf583333451ea468e8efc32387cca4595cef78 Mon Sep 17 00:00:00 2001 From: u9g Date: Fri, 18 Aug 2023 00:04:52 -0400 Subject: [PATCH] feat(query): New types added (#754) ```diff + LogicalExpression + LogicalExpression implements HasSpan + LogicalExpression implements Expression + LogicalExpression.operator + LogicalExpression.left + LogicalExpression.right + LogicalExpressionAST + LogicalExpressionAST implements LogicalExpression + LogicalExpressionAST implements ASTNode + LogicalExpressionAST implements Expression + LogicalExpressionAST implements HasSpan + Parameter implements HasSpan + UnaryExpression + UnaryExpression implements HasSpan + UnaryExpression implements Expression + UnaryExpression.operator + UnaryExpression.value + UnaryExpressionAST + UnaryExpressionAST implements ASTNode + UnaryExpressionAST implements Expression + UnaryExpressionAST implements HasSpan + UnaryExpressionAST implements UnaryExpression ``` --- crates/oxc_query/src/adapter.rs | 32 +++++++ crates/oxc_query/src/edges.rs | 124 ++++++++++++++++++++++++++++ crates/oxc_query/src/properties.rs | 54 ++++++++++++ crates/oxc_query/src/schema.graphql | 92 ++++++++++++++++++++- crates/oxc_query/src/vertex.rs | 54 ++++++++++++ 5 files changed, 355 insertions(+), 1 deletion(-) diff --git a/crates/oxc_query/src/adapter.rs b/crates/oxc_query/src/adapter.rs index 759ffebe0..de357a096 100644 --- a/crates/oxc_query/src/adapter.rs +++ b/crates/oxc_query/src/adapter.rs @@ -162,6 +162,13 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> { property_name.as_ref(), resolve_info, ), + "LogicalExpressionAST" | "LogicalExpression" => { + super::properties::resolve_logical_expression_property( + contexts, + property_name.as_ref(), + resolve_info, + ) + } "NameAST" | "Name" => super::properties::resolve_name_property( contexts, property_name.as_ref(), @@ -213,6 +220,13 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> { property_name.as_ref(), resolve_info, ), + "UnaryExpressionAST" | "UnaryExpression" => { + super::properties::resolve_unary_expression_property( + contexts, + property_name.as_ref(), + resolve_info, + ) + } _ => { unreachable!( "attempted to read property '{property_name}' on unexpected type: {type_name}" @@ -415,6 +429,15 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> { parameters, resolve_info, ), + "LogicalExpressionAST" | "LogicalExpression" => { + super::edges::resolve_logical_expression_edge( + contexts, + edge_name.as_ref(), + parameters, + resolve_info, + self, + ) + } "MemberExtend" => super::edges::resolve_member_extend_edge( contexts, edge_name.as_ref(), @@ -523,6 +546,15 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> { parameters, resolve_info, ), + "UnaryExpressionAST" | "UnaryExpression" => { + super::edges::resolve_unary_expression_edge( + contexts, + edge_name.as_ref(), + parameters, + resolve_info, + self, + ) + } "URL" => super::edges::resolve_url_edge( contexts, edge_name.as_ref(), diff --git a/crates/oxc_query/src/edges.rs b/crates/oxc_query/src/edges.rs index f420ad196..ff601e3a6 100644 --- a/crates/oxc_query/src/edges.rs +++ b/crates/oxc_query/src/edges.rs @@ -1719,6 +1719,78 @@ mod jsxtext { } } +pub(super) fn resolve_logical_expression_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 { + "span" => logical_expression::span(contexts, resolve_info), + "left" => logical_expression::left(contexts, resolve_info), + "right" => logical_expression::right(contexts, resolve_info), + "ancestor" => ancestors(contexts, adapter), + "parent" => parents(contexts, adapter), + "strip_parens" => strip_parens(contexts), + _ => { + unreachable!( + "attempted to resolve unexpected edge '{edge_name}' on type 'LogicalExpression'" + ) + } + } +} + +mod logical_expression { + use trustfall::provider::{ + resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, + VertexIterator, + }; + + use super::{super::vertex::Vertex, get_span}; + + pub(super) fn left<'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( + (&v.as_logical_expression() + .unwrap_or_else(|| { + panic!("expected to have a logical expression vertex, instead have: {v:#?}") + }) + .logical_expression + .left) + .into(), + )) + }) + } + + pub(super) fn right<'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( + (&v.as_logical_expression() + .unwrap_or_else(|| { + panic!("expected to have a logical expression vertex, instead have: {v:#?}") + }) + .logical_expression + .right) + .into(), + )) + }) + } + + 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_member_extend_edge<'a, 'b: 'a>( contexts: ContextIterator<'a, Vertex<'b>>, edge_name: &str, @@ -2564,6 +2636,58 @@ mod type_ { } } +pub(super) fn resolve_unary_expression_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 { + "span" => unary_expression::span(contexts, resolve_info), + "value" => unary_expression::value(contexts, resolve_info), + "ancestor" => ancestors(contexts, adapter), + "parent" => parents(contexts, adapter), + "strip_parens" => strip_parens(contexts), + _ => { + unreachable!("attempted to resolve unexpected edge '{edge_name}' on type 'Type_'") + } + } +} + +mod unary_expression { + use trustfall::provider::{ + 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| { + Box::new(std::iter::once( + (&v.as_unary_expression() + .unwrap_or_else(|| { + panic!("expected to have a unaryexpression vertex, instead have: {v:#?}") + }) + .unary_expression + .argument) + .into(), + )) + }) + } + + 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_url_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 01cdafd46..6f6a21c92 100644 --- a/crates/oxc_query/src/properties.rs +++ b/crates/oxc_query/src/properties.rs @@ -412,6 +412,33 @@ pub(super) fn resolve_jsxtext_property<'a, 'b: 'a>( } } +pub(super) fn resolve_logical_expression_property<'a, 'b: 'a>( + contexts: ContextIterator<'a, Vertex<'b>>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, Vertex<'b>, FieldValue> { + match property_name { + "operator" => resolve_property_with(contexts, |v| { + v.as_logical_expression() + .unwrap_or_else(|| { + panic!("expected to have a logicalexpression vertex, instead have: {v:#?}") + }) + .logical_expression + .operator + .as_str() + .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 'LogicalExpression'" + ) + } + } +} + pub(super) fn resolve_name_property<'a, 'b: 'a>( contexts: ContextIterator<'a, Vertex<'b>>, property_name: &str, @@ -654,3 +681,30 @@ pub(super) fn resolve_specific_import_property<'a, 'b: 'a>( } } } + +pub(super) fn resolve_unary_expression_property<'a, 'b: 'a>( + contexts: ContextIterator<'a, Vertex<'b>>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, Vertex<'b>, FieldValue> { + match property_name { + "operator" => resolve_property_with(contexts, |v| { + v.as_logical_expression() + .unwrap_or_else(|| { + panic!("expected to have a logicalexpression vertex, instead have: {v:#?}") + }) + .logical_expression + .operator + .as_str() + .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 'LogicalExpression'" + ) + } + } +} diff --git a/crates/oxc_query/src/schema.graphql b/crates/oxc_query/src/schema.graphql index a67429119..7b26e689b 100644 --- a/crates/oxc_query/src/schema.graphql +++ b/crates/oxc_query/src/schema.graphql @@ -514,7 +514,97 @@ interface Function implements Expression & HasSpan { span: Span! } -type Parameter { +interface UnaryExpression implements HasSpan & Expression { + """ + '+' | '-' | '!' | '~' | 'typeof' | 'void' | 'delete' + """ + operator: String! + + value: Expression! + + # 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 UnaryExpressionAST implements UnaryExpression & ASTNode & HasSpan & Expression { + """ + '+' | '-' | '!' | '~' | 'typeof' | 'void' | 'delete' + """ + operator: String! + + value: Expression! + + # 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! +} + +interface LogicalExpression implements HasSpan & Expression { + """ + '||' | '&&' | '??' + """ + operator: String! + + left: Expression! + right: Expression! + + # 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 LogicalExpressionAST implements LogicalExpression & ASTNode & HasSpan & Expression { + """ + '||' | '&&' | '??' + """ + operator: String! + + left: Expression! + right: Expression! + + # 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! +} + +type Parameter implements HasSpan { is_readonly: Boolean! assignment: AssignmentType! type_annotation: TypeAnnotation! diff --git a/crates/oxc_query/src/vertex.rs b/crates/oxc_query/src/vertex.rs index de99d0d67..b48ece525 100644 --- a/crates/oxc_query/src/vertex.rs +++ b/crates/oxc_query/src/vertex.rs @@ -56,6 +56,8 @@ pub enum Vertex<'a> { FunctionBody(Rc>), Statement(&'a Statement<'a>), Parameter(Rc>), + LogicalExpression(Rc>), + UnaryExpression(Rc>), } impl<'a> Vertex<'a> { @@ -102,6 +104,8 @@ impl<'a> Vertex<'a> { Self::FunctionBody(data) => data.function_body.span, Self::Statement(data) => data.span(), Self::Parameter(data) => data.parameter.span, + Self::LogicalExpression(data) => data.logical_expression.span, + Self::UnaryExpression(data) => data.unary_expression.span, Self::File | Self::Url(_) | Self::PathPart(_) @@ -137,6 +141,8 @@ impl<'a> Vertex<'a> { 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::LogicalExpression(data) => data.ast_node.map(|x| x.id()), + Vertex::UnaryExpression(data) => data.ast_node.map(|x| x.id()), Vertex::DefaultImport(_) | Vertex::Statement(_) | Vertex::AssignmentType(_) @@ -276,6 +282,8 @@ impl Typename for Vertex<'_> { Vertex::ArrowFunction(arrow_fn) => arrow_fn.typename(), Vertex::FunctionBody(fn_body) => fn_body.typename(), Vertex::Parameter(param) => param.typename(), + Vertex::LogicalExpression(logical_expr) => logical_expr.typename(), + Vertex::UnaryExpression(unary_expr) => unary_expr.typename(), Vertex::Statement(_) => "Statement", } } @@ -362,6 +370,12 @@ impl<'a> From> for Vertex<'a> { AstKind::Argument(argument) => { Vertex::Argument(ArgumentVertex { ast_node: Some(ast_node), argument }.into()) } + AstKind::LogicalExpression(logical_expression) => Vertex::LogicalExpression( + LogicalExpressionVertex { ast_node: Some(ast_node), logical_expression }.into(), + ), + AstKind::UnaryExpression(unary_expression) => Vertex::UnaryExpression( + UnaryExpressionVertex { ast_node: Some(ast_node), unary_expression }.into(), + ), _ => Vertex::ASTNode(ast_node), } } @@ -410,6 +424,12 @@ impl<'a> From<&'a Expression<'a>> for Vertex<'a> { Expression::ArrowExpression(arrow_expression) => Vertex::ArrowFunction( ArrowFunctionVertex { ast_node: None, arrow_expression }.into(), ), + Expression::LogicalExpression(logical_expression) => Vertex::LogicalExpression( + LogicalExpressionVertex { ast_node: None, logical_expression }.into(), + ), + Expression::UnaryExpression(unary_expression) => Vertex::UnaryExpression( + UnaryExpressionVertex { ast_node: None, unary_expression }.into(), + ), _ => Vertex::Expression(expr), } } @@ -820,3 +840,37 @@ impl<'a> Typename for ArgumentVertex<'a> { } } } + +#[non_exhaustive] +#[derive(Debug, Clone)] +pub struct LogicalExpressionVertex<'a> { + pub ast_node: Option>, + pub logical_expression: &'a LogicalExpression<'a>, +} + +impl<'a> Typename for LogicalExpressionVertex<'a> { + fn typename(&self) -> &'static str { + if self.ast_node.is_some() { + "LogicalExpressionAST" + } else { + "LogicalExpression" + } + } +} + +#[non_exhaustive] +#[derive(Debug, Clone)] +pub struct UnaryExpressionVertex<'a> { + pub ast_node: Option>, + pub unary_expression: &'a UnaryExpression<'a>, +} + +impl<'a> Typename for UnaryExpressionVertex<'a> { + fn typename(&self) -> &'static str { + if self.ast_node.is_some() { + "UnaryExpressionAST" + } else { + "UnaryExpression" + } + } +}