mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(query): add ast counterpart to ObjectLiteral (#666)
This commit is contained in:
parent
29ddca52b7
commit
228cab9269
5 changed files with 113 additions and 12 deletions
|
|
@ -136,11 +136,13 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> {
|
|||
property_name.as_ref(),
|
||||
resolve_info,
|
||||
),
|
||||
"ObjectLiteral" => super::properties::resolve_object_literal_property(
|
||||
contexts,
|
||||
property_name.as_ref(),
|
||||
resolve_info,
|
||||
),
|
||||
"ObjectLiteralAST" | "ObjectLiteral" => {
|
||||
super::properties::resolve_object_literal_property(
|
||||
contexts,
|
||||
property_name.as_ref(),
|
||||
resolve_info,
|
||||
)
|
||||
}
|
||||
"PathPart" => super::properties::resolve_path_part_property(
|
||||
contexts,
|
||||
property_name.as_ref(),
|
||||
|
|
@ -323,11 +325,12 @@ impl<'a, 'b: 'a> trustfall::provider::Adapter<'a> for &'a Adapter<'b> {
|
|||
parameters,
|
||||
resolve_info,
|
||||
),
|
||||
"ObjectLiteral" => super::edges::resolve_object_literal_edge(
|
||||
"ObjectLiteral" | "ObjectLiteralAST" => super::edges::resolve_object_literal_edge(
|
||||
contexts,
|
||||
edge_name.as_ref(),
|
||||
parameters,
|
||||
resolve_info,
|
||||
self,
|
||||
),
|
||||
"PathPart" => super::edges::resolve_path_part_edge(
|
||||
contexts,
|
||||
|
|
|
|||
|
|
@ -1272,6 +1272,7 @@ pub(super) fn resolve_object_literal_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" => object_literal::span(contexts, resolve_info),
|
||||
|
|
@ -1283,6 +1284,8 @@ pub(super) fn resolve_object_literal_edge<'a, 'b: 'a>(
|
|||
.expect("unexpected null or other incorrect datatype for Trustfall type 'String!'");
|
||||
object_literal::value(contexts, key, resolve_info)
|
||||
}
|
||||
"ancestor" => ancestors(contexts, adapter),
|
||||
"parent" => parents(contexts, adapter),
|
||||
_ => {
|
||||
unreachable!(
|
||||
"attempted to resolve unexpected edge '{edge_name}' on type 'ObjectLiteral'"
|
||||
|
|
@ -1322,7 +1325,7 @@ mod object_literal {
|
|||
panic!("expected to have an objectliteral vertex, instead have: {v:#?}")
|
||||
});
|
||||
|
||||
Box::new(obj.properties.iter().filter_map(move |property| {
|
||||
Box::new(obj.object_expression.properties.iter().filter_map(move |property| {
|
||||
let ObjectPropertyKind::ObjectProperty(prop) = property else { return None };
|
||||
|
||||
let has_right_key_name = match &prop.key {
|
||||
|
|
|
|||
|
|
@ -306,6 +306,18 @@ type ObjectLiteral implements Expression & HasSpan {
|
|||
span: Span!
|
||||
}
|
||||
|
||||
type ObjectLiteralAST implements Expression & HasSpan & ASTNode {
|
||||
value(key: String!): [Expression!]!
|
||||
|
||||
# Expression
|
||||
as_constant_string: String
|
||||
# ASTNode
|
||||
parent: ASTNode
|
||||
ancestor: [ASTNode!]!
|
||||
# HasSpan
|
||||
span: Span!
|
||||
}
|
||||
|
||||
interface Expression implements HasSpan {
|
||||
"""
|
||||
Only non-null if the string can be trivially coerced to a constant string
|
||||
|
|
|
|||
|
|
@ -138,6 +138,67 @@ query {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_object_literal_ast() {
|
||||
let code = "const colors = {blue: 1, green: 2, red: {a: 1}};";
|
||||
|
||||
let allocator = Allocator::default();
|
||||
let source_type = SourceType::default().with_module(true).with_jsx(true).with_typescript(true);
|
||||
let ret = Parser::new(&allocator, code, source_type).parse();
|
||||
let program = allocator.alloc(ret.program);
|
||||
let semantic_ret =
|
||||
SemanticBuilder::new(code, source_type).with_trivias(&ret.trivias).build(program);
|
||||
|
||||
let adapter = Adapter {
|
||||
path_components: vec![Some("index".to_string())],
|
||||
semantic: Rc::new(semantic_ret.semantic),
|
||||
};
|
||||
|
||||
let args: BTreeMap<Arc<str>, FieldValue> = BTreeMap::new();
|
||||
|
||||
let adapter = Arc::from(&adapter);
|
||||
|
||||
#[allow(clippy::items_after_statements)]
|
||||
#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, serde::Deserialize)]
|
||||
struct Output {
|
||||
__typename: String,
|
||||
value_typename: String,
|
||||
}
|
||||
|
||||
let mut results: Vec<Output> = execute_query(
|
||||
schema(),
|
||||
adapter,
|
||||
r#"
|
||||
query {
|
||||
File {
|
||||
ast_node {
|
||||
... on ObjectLiteralAST {
|
||||
value(key: "red") {
|
||||
value_typename: __typename @output
|
||||
}
|
||||
__typename @output
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
args,
|
||||
)
|
||||
.expect("to successfully execute the query")
|
||||
.map(|row| row.try_into_struct().expect("shape mismatch"))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
results.sort_unstable();
|
||||
|
||||
assert_eq!(
|
||||
vec![Output {
|
||||
__typename: "ObjectLiteralAST".to_owned(),
|
||||
value_typename: "ObjectLiteral".to_owned()
|
||||
}],
|
||||
results
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parent_query() {
|
||||
let code = "interface MyGreatInterface { myGreatProperty: number }";
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ pub enum Vertex<'a> {
|
|||
JSXSpreadAttribute(&'a JSXSpreadAttribute<'a>),
|
||||
JSXSpreadChild(&'a JSXSpreadChild<'a>),
|
||||
JSXText(&'a JSXText),
|
||||
ObjectLiteral(&'a ObjectExpression<'a>),
|
||||
ObjectLiteral(Rc<ObjectLiteralVertex<'a>>),
|
||||
PathPart(usize),
|
||||
SearchParameter(Rc<SearchParameterVertex>),
|
||||
Span(Span),
|
||||
|
|
@ -77,7 +77,7 @@ impl<'a> Vertex<'a> {
|
|||
Self::JSXSpreadAttribute(data) => data.span,
|
||||
Self::JSXSpreadChild(data) => data.span,
|
||||
Self::JSXText(data) => data.span,
|
||||
Self::ObjectLiteral(data) => data.span,
|
||||
Self::ObjectLiteral(data) => data.object_expression.span,
|
||||
Self::SpecificImport(data) => data.span,
|
||||
Self::TypeAnnotation(data) => data.type_annotation.span,
|
||||
Self::Type(data) => data.span(),
|
||||
|
|
@ -102,6 +102,7 @@ impl<'a> Vertex<'a> {
|
|||
Vertex::JSXElement(data) => data.ast_node.map(|x| x.id()),
|
||||
Vertex::TypeAnnotation(data) => data.ast_node.map(|x| x.id()),
|
||||
Vertex::VariableDeclaration(data) => data.ast_node.map(|x| x.id()),
|
||||
Vertex::ObjectLiteral(data) => data.ast_node.map(|x| x.id()),
|
||||
Vertex::ReturnStatementAST(data) => data.ast_node.map(|x| x.id()),
|
||||
Vertex::DefaultImport(_)
|
||||
| Vertex::AssignmentType(_)
|
||||
|
|
@ -112,7 +113,6 @@ impl<'a> Vertex<'a> {
|
|||
| Vertex::JSXAttribute(_)
|
||||
| Vertex::JSXExpressionContainer(_)
|
||||
| Vertex::JSXFragment(_)
|
||||
| Vertex::ObjectLiteral(_)
|
||||
| Vertex::JSXText(_)
|
||||
| Vertex::JSXSpreadChild(_)
|
||||
| Vertex::JSXSpreadAttribute(_)
|
||||
|
|
@ -168,7 +168,7 @@ impl Typename for Vertex<'_> {
|
|||
Vertex::JSXSpreadAttribute(_) => "JSXSpreadAttribute",
|
||||
Vertex::JSXSpreadChild(_) => "JSXSpreadChild",
|
||||
Vertex::JSXText(_) => "JSXText",
|
||||
Vertex::ObjectLiteral(_) => "ObjectLiteral",
|
||||
Vertex::ObjectLiteral(objlit) => objlit.typename(),
|
||||
Vertex::PathPart(_) => "PathPart",
|
||||
Vertex::SearchParameter(_) => "SearchParameter",
|
||||
Vertex::Span(_) => "Span",
|
||||
|
|
@ -206,6 +206,9 @@ impl<'a> From<AstNode<'a>> for Vertex<'a> {
|
|||
AstKind::Class(class) => {
|
||||
Self::Class(ClassVertex { ast_node: Some(ast_node), class }.into())
|
||||
}
|
||||
AstKind::ObjectExpression(objexpr) => Self::ObjectLiteral(
|
||||
ObjectLiteralVertex { ast_node: Some(ast_node), object_expression: objexpr }.into(),
|
||||
),
|
||||
_ => Vertex::ASTNode(ast_node),
|
||||
}
|
||||
}
|
||||
|
|
@ -217,7 +220,9 @@ impl<'a> From<&'a Expression<'a>> for Vertex<'a> {
|
|||
|
||||
// NOTE: When string literal / template literal is added, add to as_constant_string
|
||||
match &expr.get_inner_expression() {
|
||||
Expression::ObjectExpression(objexpr) => Vertex::ObjectLiteral(objexpr),
|
||||
Expression::ObjectExpression(object_expression) => Vertex::ObjectLiteral(
|
||||
ObjectLiteralVertex { ast_node: None, object_expression }.into(),
|
||||
),
|
||||
Expression::JSXElement(element) => {
|
||||
Vertex::JSXElement(JSXElementVertex { ast_node: None, element }.into())
|
||||
}
|
||||
|
|
@ -376,3 +381,20 @@ impl<'a> Typename for VariableDeclarationVertex<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ObjectLiteralVertex<'a> {
|
||||
ast_node: Option<AstNode<'a>>,
|
||||
pub object_expression: &'a ObjectExpression<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Typename for ObjectLiteralVertex<'a> {
|
||||
fn typename(&self) -> &'static str {
|
||||
if self.ast_node.is_some() {
|
||||
"ObjectLiteralAST"
|
||||
} else {
|
||||
"ObjectLiteral"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue