feat(query): Add Reassignment type and add str property to span (#731)

This commit is contained in:
u9g 2023-08-13 10:18:41 -04:00 committed by GitHub
parent 5e9927745e
commit 087abd3cf1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 233 additions and 152 deletions

View file

@ -31,7 +31,7 @@ pub const SCHEMA_TEXT: &str = include_str!("./schema.graphql");
/// If the schema parse returns an error, which will not happen unless the schema get's corrupted.
pub fn schema() -> &'static Schema {
// internal note: this might not parser correctly due to making an incorrect schema during development
SCHEMA.get_or_init(|| Schema::parse(SCHEMA_TEXT).expect("not a valid schema"))
SCHEMA.get_or_init(|| Schema::parse(SCHEMA_TEXT).unwrap_or_else(|e| panic!("{}", e)))
}
impl<'a> Adapter<'a> {
@ -116,11 +116,6 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> {
property_name.as_ref(),
resolve_info,
),
"InterfaceExtend" => super::properties::resolve_interface_extend_property(
contexts,
property_name.as_ref(),
resolve_info,
),
"JSXAttribute" => super::properties::resolve_jsxattribute_property(
contexts,
property_name.as_ref(),
@ -143,11 +138,6 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> {
property_name.as_ref(),
resolve_info,
),
"MemberExtend" => super::properties::resolve_member_extend_property(
contexts,
property_name.as_ref(),
resolve_info,
),
"NameAST" | "Name" => super::properties::resolve_name_property(
contexts,
property_name.as_ref(),
@ -173,12 +163,12 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> {
resolve_info,
self,
),
"SearchParameter" => super::properties::resolve_search_parameter_property(
"ReassignmentAST" | "Reassignment" => super::properties::resolve_reassignment_property(
contexts,
property_name.as_ref(),
resolve_info,
),
"SimpleExtend" => super::properties::resolve_simple_extend_property(
"SearchParameter" => super::properties::resolve_search_parameter_property(
contexts,
property_name.as_ref(),
resolve_info,
@ -187,18 +177,13 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> {
contexts,
property_name.as_ref(),
resolve_info,
self,
),
"SpecificImport" => super::properties::resolve_specific_import_property(
contexts,
property_name.as_ref(),
resolve_info,
),
"Type" => super::properties::resolve_type_property(
contexts,
property_name.as_ref(),
resolve_info,
self,
),
_ => {
unreachable!(
"attempted to read property '{property_name}' on unexpected type: {type_name}"
@ -407,6 +392,13 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> {
resolve_info,
self,
),
"ReassignmentAST" | "Reassignment" => super::edges::resolve_reassignment_edge(
contexts,
edge_name.as_ref(),
parameters,
resolve_info,
self,
),
"ReturnStatementAST" => super::edges::resolve_return_statement_ast_edge(
contexts,
edge_name.as_ref(),

View file

@ -1745,6 +1745,105 @@ mod path_part {
}
}
pub(super) fn resolve_reassignment_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 {
"parent" => parents(contexts, adapter),
"ancestor" => ancestors(contexts, adapter),
"span" => reassignment::span(contexts, resolve_info),
"left_as_expression" => reassignment::left_as_expression(contexts, resolve_info),
"right" => reassignment::right(contexts, resolve_info),
_ => {
unreachable!(
"attempted to resolve unexpected edge '{edge_name}' on type 'Reassignment'"
)
}
}
}
mod reassignment {
use std::convert::Into;
use trustfall::provider::{
resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo,
VertexIterator,
};
use super::super::vertex::Vertex;
pub(super) fn left_as_expression<'a, 'b: 'a>(
contexts: ContextIterator<'a, Vertex<'b>>,
_resolve_info: &ResolveEdgeInfo,
) -> ContextOutcomeIterator<'a, Vertex<'b>, VertexIterator<'a, Vertex<'b>>> {
resolve_neighbors_with(contexts, |v| {
match &v
.as_reassignment()
.unwrap_or_else(|| {
panic!("expected to have a reassignment vertex, instead have: {v:#?}")
})
.assignment_expression
.left
{
oxc_ast::ast::AssignmentTarget::SimpleAssignmentTarget(target) => {
let expr = match target {
oxc_ast::ast::SimpleAssignmentTarget::AssignmentTargetIdentifier(
assignment_target,
) => Vertex::try_from_identifier_reference(assignment_target),
oxc_ast::ast::SimpleAssignmentTarget::MemberAssignmentTarget(membexpr) => {
Vertex::try_from_member_expression(membexpr)
}
oxc_ast::ast::SimpleAssignmentTarget::TSAsExpression(it) => {
Some((&it.expression).into())
}
oxc_ast::ast::SimpleAssignmentTarget::TSSatisfiesExpression(it) => {
Some((&it.expression).into())
}
oxc_ast::ast::SimpleAssignmentTarget::TSNonNullExpression(it) => {
Some((&it.expression).into())
}
oxc_ast::ast::SimpleAssignmentTarget::TSTypeAssertion(it) => {
Some((&it.expression).into())
}
};
Box::new(expr.into_iter().map(Into::into))
}
oxc_ast::ast::AssignmentTarget::AssignmentTargetPattern(_) => {
Box::new(std::iter::empty())
}
}
})
}
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_reassignment()
.unwrap_or_else(|| {
panic!("expected to have a reassignment vertex, instead have: {v:#?}")
})
.assignment_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>>> {
super::get_span(contexts)
}
}
pub(super) fn resolve_return_statement_ast_edge<'a, 'b: 'a>(
contexts: ContextIterator<'a, Vertex<'b>>,
edge_name: &str,

View file

@ -1,7 +1,6 @@
use std::convert::Into;
use oxc_ast::ast::{BindingPatternKind, Expression, MemberExpression};
use oxc_span::GetSpan;
use oxc_ast::ast::{BindingPatternKind, Expression};
use trustfall::{
provider::{
field_property, resolve_property_with, ContextIterator, ContextOutcomeIterator, ResolveInfo,
@ -15,49 +14,9 @@ use crate::{
accessibility_to_string, jsx_attribute_name_to_string, jsx_attribute_to_constant_string,
jsx_element_name_to_string,
},
vertex::InterfaceExtendVertex,
Adapter,
};
fn interface_extend_implem<'a, 'b: 'a>(
contexts: ContextIterator<'a, Vertex<'b>>,
) -> ContextOutcomeIterator<'a, Vertex<'b>, FieldValue> {
resolve_property_with(contexts, |v| {
match v
.as_interface_extend()
.unwrap_or_else(|| {
panic!("expected to have an interfaceextend vertex, instead have: {v:#?}")
})
.as_ref()
{
InterfaceExtendVertex::Identifier(ident) => ident.name.to_string(),
InterfaceExtendVertex::MemberExpression(first_membexpr) => {
let MemberExpression::StaticMemberExpression(static_membexpr) = first_membexpr
else {
unreachable!("TS:2499")
};
let mut parts = vec![static_membexpr.property.name.to_string()];
let mut membexpr = first_membexpr.object();
while let Expression::MemberExpression(expr) = membexpr {
let MemberExpression::StaticMemberExpression(static_membexpr) = &expr.0 else {
unreachable!("TS:2499")
};
parts.push(static_membexpr.property.name.to_string());
membexpr = expr.object();
}
let Expression::Identifier(ident) = membexpr else { unreachable!("TS:2499") };
parts.push(ident.name.to_string());
parts.reverse();
parts.join(".")
}
}
.into()
})
}
pub(super) fn resolve_assignment_type_property<'a, 'b: 'a>(
contexts: ContextIterator<'a, Vertex<'b>>,
property_name: &str,
@ -270,21 +229,6 @@ pub(super) fn resolve_interface_property<'a, 'b: 'a>(
}
}
pub(super) fn resolve_interface_extend_property<'a, 'b: 'a>(
contexts: ContextIterator<'a, Vertex<'b>>,
property_name: &str,
_resolve_info: &ResolveInfo,
) -> ContextOutcomeIterator<'a, Vertex<'b>, FieldValue> {
match property_name {
"str" => interface_extend_implem(contexts),
_ => {
unreachable!(
"attempted to read unexpected property '{property_name}' on type 'InterfaceExtend'"
)
}
}
}
pub(super) fn resolve_jsxattribute_property<'a, 'b: 'a>(
contexts: ContextIterator<'a, Vertex<'b>>,
property_name: &str,
@ -386,21 +330,6 @@ pub(super) fn resolve_jsxtext_property<'a, 'b: 'a>(
}
}
pub(super) fn resolve_member_extend_property<'a, 'b: 'a>(
contexts: ContextIterator<'a, Vertex<'b>>,
property_name: &str,
_resolve_info: &ResolveInfo,
) -> ContextOutcomeIterator<'a, Vertex<'b>, FieldValue> {
match property_name {
"str" => interface_extend_implem(contexts),
_ => {
unreachable!(
"attempted to read unexpected property '{property_name}' on type 'MemberExtend'"
)
}
}
}
pub(super) fn resolve_name_property<'a, 'b: 'a>(
contexts: ContextIterator<'a, Vertex<'b>>,
property_name: &str,
@ -507,6 +436,23 @@ pub(super) fn resolve_path_part_property<'a, 'b: 'a>(
}
}
pub(super) fn resolve_reassignment_property<'a, 'b: 'a>(
contexts: ContextIterator<'a, Vertex<'b>>,
property_name: &str,
_resolve_info: &ResolveInfo,
) -> ContextOutcomeIterator<'a, Vertex<'b>, FieldValue> {
match property_name {
"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 'Reassignment'"
)
}
}
}
pub(super) fn resolve_search_parameter_property<'a, 'b: 'a>(
contexts: ContextIterator<'a, Vertex<'b>>,
property_name: &str,
@ -539,27 +485,19 @@ pub(super) fn resolve_search_parameter_property<'a, 'b: 'a>(
}
}
pub(super) fn resolve_simple_extend_property<'a, 'b: 'a>(
contexts: ContextIterator<'a, Vertex<'b>>,
property_name: &str,
_resolve_info: &ResolveInfo,
) -> ContextOutcomeIterator<'a, Vertex<'b>, FieldValue> {
match property_name {
"str" => interface_extend_implem(contexts),
_ => {
unreachable!(
"attempted to read unexpected property '{property_name}' on type 'SimpleExtend'"
)
}
}
}
pub(super) fn resolve_span_property<'a, 'b: 'a>(
contexts: ContextIterator<'a, Vertex<'b>>,
property_name: &str,
_resolve_info: &ResolveInfo,
adapter: &'a Adapter<'b>,
) -> ContextOutcomeIterator<'a, Vertex<'b>, FieldValue> {
match property_name {
"str" => resolve_property_with(contexts, |v| {
let span = v
.as_span()
.unwrap_or_else(|| panic!("expected to have a span vertex, instead have: {v:#?}"));
adapter.semantic.source_text()[span.start as usize..span.end as usize].into()
}),
"end" => resolve_property_with(contexts, |v| {
v.as_span()
.unwrap_or_else(|| panic!("expected to have a span vertex, instead have: {v:#?}"))
@ -611,23 +549,3 @@ pub(super) fn resolve_specific_import_property<'a, 'b: 'a>(
}
}
}
pub(super) fn resolve_type_property<'a, 'b: 'a>(
contexts: ContextIterator<'a, Vertex<'b>>,
property_name: &str,
_resolve_info: &ResolveInfo,
adapter: &'a Adapter<'b>,
) -> ContextOutcomeIterator<'a, Vertex<'b>, FieldValue> {
match property_name {
"str" => resolve_property_with(contexts, |v| {
let span = v
.as_type()
.unwrap_or_else(|| panic!("expected to have a type vertex, instead have: {v:#?}"))
.span();
adapter.semantic.source_text()[span.start as usize..span.end as usize].into()
}),
_ => {
unreachable!("attempted to read unexpected property '{property_name}' on type 'Type'")
}
}
}

View file

@ -179,7 +179,6 @@ interface A extends B.C {}
B.C is always more than one identifier.
"""
type MemberExtend implements InterfaceExtend {
str: String!
span: Span!
}
@ -188,15 +187,10 @@ interface A extends B {}
B is always just one identifier.
"""
type SimpleExtend implements InterfaceExtend {
str: String!
span: Span!
}
interface InterfaceExtend {
"""
Null if not decidabled such as
"""
str: String
span: Span!
}
@ -248,7 +242,6 @@ interface Class {
}
interface Type {
str: String!
span: Span!
}
@ -260,6 +253,7 @@ interface TypeAnnotation implements HasSpan {
type Span {
start: Int!
end: Int!
str: String!
}
type JSXSpreadChild {
@ -392,6 +386,43 @@ type ObjectLiteralAST implements ObjectLiteral & Expression & HasSpan & ASTNode
span: Span!
}
"""
Any assignment that isn't a variable declaration, which means no const/let/var.
ie: "a = 1;", "a /= 1;", "a += 1;", etc.
"""
interface Reassignment implements HasSpan & Expression {
"""
Only nonnull if the left is not an object or array destructuring.
examples that this would be usable: "a = 12;", "a.b = 'apple';"
"""
left_as_expression: Expression
right: Expression!
# Expression
as_constant_string: String
# HasSpan
span: Span!
}
"""
Any assignment that isn't a variable declaration, which means no const/let/var.
ie: "a = 1;", "a /= 1;", "a += 1;", etc.
"""
type ReassignmentAST implements HasSpan & ASTNode & Reassignment & Expression {
"""
Only nonnull if the left is not an object or array destructuring.
examples that this would be usable: "a = 12;", "a.b = 'apple';"
"""
left_as_expression: Expression
right: Expression!
# Expression
as_constant_string: String
# HasSpan
span: Span!
# ASTNode
parent: ASTNode
ancestor: [ASTNode!]!
}
interface Name implements HasSpan {
name: String!
# HasSpan

View file

@ -164,7 +164,9 @@ fn test_parent_query() {
ast_node {
... on TypeAnnotationAST {
type {
type_: str @output
span {
type_: str @output
}
}
parent {
tn1: __typename @output

View file

@ -3,13 +3,13 @@ use std::rc::Rc;
use enum_as_inner::EnumAsInner;
use oxc_ast::{
ast::{
BindingPatternKind, Class, Expression, IdentifierName, IdentifierReference, IfStatement,
ImportDeclaration, ImportDefaultSpecifier, ImportSpecifier, JSXAttribute, JSXElement,
JSXExpressionContainer, JSXFragment, JSXOpeningElement, JSXSpreadAttribute, JSXSpreadChild,
JSXText, MemberExpression, MethodDefinition, ModuleDeclaration, NumberLiteral,
ObjectExpression, ObjectProperty, PropertyDefinition, ReturnStatement, SpreadElement,
StaticMemberExpression, TSInterfaceDeclaration, TSType, TSTypeAnnotation,
VariableDeclarator,
AssignmentExpression, BindingPatternKind, Class, Expression, IdentifierName,
IdentifierReference, IfStatement, ImportDeclaration, ImportDefaultSpecifier,
ImportSpecifier, JSXAttribute, JSXElement, JSXExpressionContainer, JSXFragment,
JSXOpeningElement, JSXSpreadAttribute, JSXSpreadChild, JSXText, MemberExpression,
MethodDefinition, ModuleDeclaration, NumberLiteral, ObjectExpression, ObjectProperty,
PropertyDefinition, ReturnStatement, SpreadElement, StaticMemberExpression,
TSInterfaceDeclaration, TSType, TSTypeAnnotation, VariableDeclarator,
},
AstKind,
};
@ -58,6 +58,7 @@ pub enum Vertex<'a> {
SpreadIntoObject(Rc<SpreadIntoObjectVertex<'a>>),
ObjectEntry(Rc<ObjectEntryVertex<'a>>),
DotProperty(Rc<DotPropertyVertex<'a>>),
Reassignment(Rc<ReassignmentVertex<'a>>),
}
impl<'a> Vertex<'a> {
@ -95,6 +96,7 @@ impl<'a> Vertex<'a> {
Self::ReturnStatementAST(data) => data.return_statement.span,
Self::IfStatementAST(data) => data.return_statement.span,
Self::NumberLiteral(data) => data.number_literal.span,
Self::Reassignment(data) => data.assignment_expression.span,
Self::Name(data) => data.name.span,
Self::File
| Self::Url(_)
@ -124,6 +126,7 @@ impl<'a> Vertex<'a> {
Vertex::SpreadIntoObject(data) => data.ast_node.map(|x| x.id()),
Vertex::ObjectEntry(data) => data.ast_node.map(|x| x.id()),
Vertex::DotProperty(data) => data.ast_node.map(|x| x.id()),
Vertex::Reassignment(data) => data.ast_node.map(|x| x.id()),
Vertex::DefaultImport(_)
| Vertex::AssignmentType(_)
| Vertex::ClassMethod(_)
@ -160,6 +163,25 @@ impl<'a> Vertex<'a> {
_ => None,
}
}
// todo: remove `Option` when the match covers all the cases
pub fn try_from_member_expression(member_expression: &'a MemberExpression<'a>) -> Option<Self> {
match &member_expression {
MemberExpression::StaticMemberExpression(static_member_expr) => {
Some(Vertex::DotProperty(
DotPropertyVertex { ast_node: None, static_member_expr }.into(),
))
}
_ => None,
}
}
// todo: remove `Option` when this doesn't return none
pub fn try_from_identifier_reference(
_identifier_reference: &'a IdentifierReference,
) -> Option<Self> {
None
}
}
impl Typename for Vertex<'_> {
@ -203,6 +225,7 @@ impl Typename for Vertex<'_> {
Vertex::IfStatementAST(_) => "IfStatementAST",
Vertex::SpreadIntoObject(obj) => obj.typename(),
Vertex::ObjectEntry(entry) => entry.typename(),
Vertex::Reassignment(reassignment) => reassignment.typename(),
}
}
}
@ -267,6 +290,9 @@ impl<'a> From<AstNode<'a>> for Vertex<'a> {
_ => unreachable!("we should only ever have StaticMemberExpression"),
}
}
AstKind::AssignmentExpression(assignment_expression) => Vertex::Reassignment(
ReassignmentVertex { ast_node: Some(ast_node), assignment_expression }.into(),
),
_ => Vertex::ASTNode(ast_node),
}
}
@ -287,18 +313,14 @@ impl<'a> From<&'a Expression<'a>> for Vertex<'a> {
Expression::NumberLiteral(number_literal) => {
Vertex::NumberLiteral(NumberLiteralVertex { ast_node: None, number_literal }.into())
}
Expression::MemberExpression(member_expr)
if matches!(**member_expr, MemberExpression::StaticMemberExpression(_)) =>
{
match &**member_expr {
MemberExpression::StaticMemberExpression(static_member_expr) => {
Vertex::DotProperty(
DotPropertyVertex { ast_node: None, static_member_expr }.into(),
)
}
_ => unreachable!("we should only ever have StaticMemberExpression"),
}
Expression::MemberExpression(me) => {
let vertex = Vertex::try_from_member_expression(me);
vertex.unwrap_or(Vertex::Expression(expr))
}
Expression::AssignmentExpression(assignment_expression) => Vertex::Reassignment(
ReassignmentVertex { ast_node: None, assignment_expression }.into(),
),
_ => Vertex::Expression(expr),
}
}
@ -580,3 +602,20 @@ impl<'a> Typename for DotPropertyVertex<'a> {
}
}
}
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct ReassignmentVertex<'a> {
ast_node: Option<AstNode<'a>>,
pub assignment_expression: &'a AssignmentExpression<'a>,
}
impl<'a> Typename for ReassignmentVertex<'a> {
fn typename(&self) -> &'static str {
if self.ast_node.is_some() {
"ReassignmentAST"
} else {
"Reassignment"
}
}
}