diff --git a/crates/txtx-addon-kit/src/helpers/hcl.rs b/crates/txtx-addon-kit/src/helpers/hcl.rs index dd64cb509..550894062 100644 --- a/crates/txtx-addon-kit/src/helpers/hcl.rs +++ b/crates/txtx-addon-kit/src/helpers/hcl.rs @@ -1,6 +1,9 @@ use std::collections::VecDeque; -use hcl_edit::{expr::Object, structure::Body}; +use hcl_edit::{ + structure::{Attribute, Body}, + Span, +}; use crate::{ hcl::{ @@ -50,7 +53,7 @@ pub fn visit_optional_string_attribute( } } -pub fn visit_required_string_literal_attribute( +fn visit_required_string_literal_attribute( field_name: &str, block: &Block, ) -> Result { @@ -71,13 +74,6 @@ pub fn visit_optional_untyped_attribute(field_name: &str, block: &Block) -> Opti Some(attribute.value.clone()) } -pub fn get_object_expression_key(obj: &Object, key: &str) -> Option { - obj.into_iter() - .find(|(k, _)| k.as_ident().and_then(|i| Some(i.as_str().eq(key))).unwrap_or(false)) - .map(|(_, v)| v) - .cloned() -} - pub fn build_diagnostics_for_unused_fields( fields_names: Vec<&str>, block: &Block, @@ -98,20 +94,21 @@ pub fn build_diagnostics_for_unused_fields( /// Takes an HCL block and traverses all inner expressions and blocks, /// recursively collecting all the references to constructs (variables and traversals). -pub fn collect_constructs_references_from_block<'a, T: EvaluatableInput>( - block: &Block, +pub fn collect_constructs_referenced_by_construct<'a, T: EvaluatableInput>( + construct: &RunbookConstruct, input: Option<&'a T>, dependencies: &mut Vec<(Option<&'a T>, Expression)>, ) { - for attribute in block.body.attributes() { - let expr = attribute.value.clone(); - let mut references = vec![]; - collect_constructs_references_from_expression(&expr, input, &mut references); - dependencies.append(&mut references); - } - for block in block.body.blocks() { - collect_constructs_references_from_block(block, input, dependencies); - } + unimplemented!() + // for attribute in construct.get_attributes() { + // let expr = attribute.get_value(); + // let mut references = vec![]; + // expr.collect_constructs_references_from_expression(input, &mut references); + // dependencies.append(&mut references); + // } + // for sub_construct in construct.get_sub_constructs() { + // collect_constructs_referenced_by_construct(sub_construct, input, dependencies); + // } } /// Takes an HCL expression and boils it down to a Variable or Traversal expression, @@ -120,7 +117,7 @@ pub fn collect_constructs_references_from_block<'a, T: EvaluatableInput>( /// val = [variable.a, variable.b] /// ``` /// will push `variable.a` and `variable.b` to the dependencies vector. -pub fn collect_constructs_references_from_expression<'a, T: EvaluatableInput>( +pub fn collect_constructs_references_from_hcl_expression<'a, T: EvaluatableInput>( expr: &Expression, input: Option<&'a T>, dependencies: &mut Vec<(Option<&'a T>, Expression)>, @@ -131,38 +128,42 @@ pub fn collect_constructs_references_from_expression<'a, T: EvaluatableInput>( } Expression::Array(elements) => { for element in elements.iter() { - collect_constructs_references_from_expression(element, input, dependencies); + collect_constructs_references_from_hcl_expression(element, input, dependencies); } } Expression::BinaryOp(op) => { - collect_constructs_references_from_expression(&op.lhs_expr, input, dependencies); - collect_constructs_references_from_expression(&op.rhs_expr, input, dependencies); + collect_constructs_references_from_hcl_expression(&op.lhs_expr, input, dependencies); + collect_constructs_references_from_hcl_expression(&op.rhs_expr, input, dependencies); } Expression::Bool(_) | Expression::Null(_) | Expression::Number(_) | Expression::String(_) => return, Expression::Conditional(cond) => { - collect_constructs_references_from_expression(&cond.cond_expr, input, dependencies); - collect_constructs_references_from_expression(&cond.false_expr, input, dependencies); - collect_constructs_references_from_expression(&cond.true_expr, input, dependencies); + collect_constructs_references_from_hcl_expression(&cond.cond_expr, input, dependencies); + collect_constructs_references_from_hcl_expression( + &cond.false_expr, + input, + dependencies, + ); + collect_constructs_references_from_hcl_expression(&cond.true_expr, input, dependencies); } Expression::ForExpr(for_expr) => { - collect_constructs_references_from_expression( + collect_constructs_references_from_hcl_expression( &for_expr.value_expr, input, dependencies, ); if let Some(ref key_expr) = for_expr.key_expr { - collect_constructs_references_from_expression(&key_expr, input, dependencies); + collect_constructs_references_from_hcl_expression(&key_expr, input, dependencies); } if let Some(ref cond) = for_expr.cond { - collect_constructs_references_from_expression(&cond.expr, input, dependencies); + collect_constructs_references_from_hcl_expression(&cond.expr, input, dependencies); } } Expression::FuncCall(expr) => { for arg in expr.args.iter() { - collect_constructs_references_from_expression(arg, input, dependencies); + collect_constructs_references_from_hcl_expression(arg, input, dependencies); } } Expression::HeredocTemplate(expr) => { @@ -170,7 +171,7 @@ pub fn collect_constructs_references_from_expression<'a, T: EvaluatableInput>( match element { Element::Directive(_) | Element::Literal(_) => {} Element::Interpolation(interpolation) => { - collect_constructs_references_from_expression( + collect_constructs_references_from_hcl_expression( &interpolation.expr, input, dependencies, @@ -183,22 +184,26 @@ pub fn collect_constructs_references_from_expression<'a, T: EvaluatableInput>( for (k, v) in obj.iter() { match k { ObjectKey::Expression(expr) => { - collect_constructs_references_from_expression(&expr, input, dependencies); + collect_constructs_references_from_hcl_expression( + &expr, + input, + dependencies, + ); } ObjectKey::Ident(_) => {} } - collect_constructs_references_from_expression(&v.expr(), input, dependencies); + collect_constructs_references_from_hcl_expression(&v.expr(), input, dependencies); } } Expression::Parenthesis(expr) => { - collect_constructs_references_from_expression(&expr.inner(), input, dependencies); + collect_constructs_references_from_hcl_expression(&expr.inner(), input, dependencies); } Expression::StringTemplate(template) => { for element in template.iter() { match element { Element::Directive(_) | Element::Literal(_) => {} Element::Interpolation(interpolation) => { - collect_constructs_references_from_expression( + collect_constructs_references_from_hcl_expression( &interpolation.expr, input, dependencies, @@ -214,35 +219,395 @@ pub fn collect_constructs_references_from_expression<'a, T: EvaluatableInput>( dependencies.push((input.clone(), expr.clone())); } Expression::UnaryOp(op) => { - collect_constructs_references_from_expression(&op.expr, input, dependencies); + collect_constructs_references_from_hcl_expression(&op.expr, input, dependencies); + } + } +} + +#[derive(Debug, Clone)] +pub enum ConstructAttributeRef<'a> { + Hcl(&'a Attribute), + Json(), + Yaml(), +} + +impl<'a> ConstructAttributeRef<'a> { + pub fn get_value(&self) -> ConstructExpression { + match &self { + Self::Hcl(expr) => ConstructExpression::Hcl(expr.value.clone()), + _ => unimplemented!(), + } + } +} + +#[derive(Debug, Clone)] +pub enum ConstructExpression { + Hcl(Expression), + Json(), + Yaml(), +} + +#[derive(Debug, Clone)] +pub enum ConstructExpressionRef<'a> { + Hcl(&'a Expression), + Json(), + Yaml(), +} + +impl<'a> From> for ConstructExpression { + fn from(value: ConstructExpressionRef<'a>) -> Self { + match value { + ConstructExpressionRef::Hcl(expr_ref) => ConstructExpression::Hcl(expr_ref.clone()), + ConstructExpressionRef::Json() => ConstructExpression::Json(), + ConstructExpressionRef::Yaml() => ConstructExpression::Yaml(), + } + } +} + +impl<'a> From<&'a ConstructExpression> for ConstructExpressionRef<'a> { + fn from(value: &'a ConstructExpression) -> Self { + match value { + ConstructExpression::Hcl(expr) => ConstructExpressionRef::Hcl(expr), + ConstructExpression::Json() => ConstructExpressionRef::Json(), + ConstructExpression::Yaml() => ConstructExpressionRef::Yaml(), + } + } +} + +impl<'a> ConstructExpression { + pub fn collect_constructs_references_from_expression( + &self, + input: Option<&'a T>, + dependencies: &mut Vec<(Option<&'a T>, Expression)>, + ) { + match &self { + Self::Hcl(expr) => { + collect_constructs_references_from_hcl_expression(&expr, input, dependencies) + } + _ => unimplemented!(), + } + } + + pub fn get_object_expression_key(&self, key: &str) -> Option { + match &self { + Self::Hcl(expr) => { + let object_expr = expr.as_object().unwrap(); + let expr_res = object_expr + .into_iter() + .find(|(k, _)| { + k.as_ident().and_then(|i| Some(i.as_str().eq(key))).unwrap_or(false) + }) + .map(|(_, v)| v) + .cloned(); + match expr_res { + Some(expression) => Some(ConstructExpression::Hcl(expression.expr().clone())), + None => None, + } + } + _ => unimplemented!(), + } + } + + pub fn expect_hcl_expression(&self) -> &Expression { + let expr = match &self { + Self::Hcl(src) => src, + _ => unimplemented!(), + }; + expr + } +} + +#[derive(Debug, Clone)] +pub enum RunbookConstruct { + Hcl(Block), + Json(), + Yaml(), +} + +#[derive(Debug, Clone)] +pub enum RunbookConstructRef<'a> { + Hcl(&'a Block), + Json(), + Yaml(), +} + +impl<'a> From> for RunbookConstruct { + fn from(value: RunbookConstructRef<'a>) -> Self { + match value { + RunbookConstructRef::Hcl(block_ref) => RunbookConstruct::Hcl(block_ref.clone()), + RunbookConstructRef::Json() => RunbookConstruct::Json(), + RunbookConstructRef::Yaml() => RunbookConstruct::Yaml(), + } + } +} + +impl<'a> From<&'a RunbookConstruct> for RunbookConstructRef<'a> { + fn from(value: &'a RunbookConstruct) -> Self { + match value { + RunbookConstruct::Hcl(block) => RunbookConstructRef::Hcl(block), + RunbookConstruct::Json() => RunbookConstructRef::Json(), + RunbookConstruct::Yaml() => RunbookConstructRef::Yaml(), + } + } +} +impl<'a> RunbookConstructRef<'a> { + pub fn get_sub_constructs(&'a self) -> Objects<'a> { + match &self { + Self::Hcl(block) => { + block.body.blocks().map(|b: &Block| RunbookConstructRef::Hcl(b)).collect::>() + } + _ => unimplemented!(), } } + + pub fn get_attributes(&'a self) -> Vec> { + match &self { + Self::Hcl(block) => { + block.body.attributes().map(|b| ConstructAttributeRef::Hcl(b)).collect::>() + } + _ => unimplemented!(), + } + } + + pub fn get_sub_constructs_type(&'a self, sub_constructs_type: &'a str) -> Objects<'a> { + match &self { + Self::Hcl(block) => block + .body + .get_blocks(sub_constructs_type) + .map(|b: &Block| RunbookConstructRef::Hcl(b)) + .collect::>(), + _ => unimplemented!(), + } + } + + pub fn get_expression_from_attribute( + &'a self, + attribute_name: &str, + ) -> Option> { + match &self { + Self::Hcl(block) => { + let Some(attribute) = block.body.get_attribute(attribute_name) else { + return None; + }; + Some(ConstructExpressionRef::Hcl(&attribute.value)) + } + _ => unimplemented!(), + } + } + + // pub fn collect_constructs_referenced_by_construct<'b, T: EvaluatableInput>( + // &self, + // input: Option<&'b T>, + // dependencies: &'b mut Vec<(Option<&'b T>, Expression)>, + // ) { + // for attribute in self.get_attributes() { + // let expr = attribute.get_value(); + // let mut references = vec![]; + // expr.collect_constructs_references_from_expression(input, &mut references); + // dependencies.append(&mut references); + // } + // for sub_constructs in self.get_sub_constructs() { + // sub_constructs.collect_constructs_referenced_by_construct(input, dependencies); + // } + // } +} + +pub type Objects<'a> = Vec>; + +impl RunbookConstruct { + pub fn get_construct_type(&self) -> &str { + match &self { + Self::Hcl(src) => src.ident.value().as_str(), + _ => unimplemented!(), + } + } + + pub fn get_construct_instance_name(&self) -> Option<&str> { + match &self { + Self::Hcl(block) => { + let Some(BlockLabel::String(name)) = block.labels.get(0) else { return None }; + Some(name.as_str()) + } + _ => unimplemented!(), + } + } + + pub fn get_attributes<'a>(&'a self) -> Vec> { + match &self { + Self::Hcl(block) => { + block.body.attributes().map(|b| ConstructAttributeRef::Hcl(b)).collect::>() + } + _ => unimplemented!(), + } + } + + // pub fn get_attribute<'a>(&'a self, attribute_name: &str, expected_type: Option) -> Option> { + // match &self { + // Self::Hcl(block) => { + // let value = block.body.get_attribute(attribute_name).map(|b| ConstructAttributeRef::Hcl(b))?; + // match expected_type { + // None => Some(value), + // Some(Type::String) => + // } + // } + // _ => unimplemented!(), + // } + // } + + pub fn get_attribute_stringified(&self, attribute_name: &str) -> Option { + match &self { + Self::Hcl(block) => { + block.body.get_attribute(attribute_name).map(|b| b.value.to_string()) + } + _ => unimplemented!(), + } + } + + pub fn get_command_instance_type(&self) -> Option<&str> { + match &self { + Self::Hcl(block) => { + let Some(BlockLabel::String(name)) = block.labels.get(1) else { return None }; + Some(name.as_str()) + } + _ => unimplemented!(), + } + } + + pub fn get_sub_constructs<'a>(&'a self) -> Objects<'a> { + match &self { + Self::Hcl(block) => { + block.body.blocks().map(|b: &Block| RunbookConstructRef::Hcl(b)).collect::>() + } + _ => unimplemented!(), + } + } + + pub fn get_sub_constructs_type<'a>( + &'a self, + sub_constructs_type: &'a str, + ) -> Vec { + match &self { + Self::Hcl(block) => block + .body + .get_blocks(sub_constructs_type) + .map(|b: &Block| RunbookConstruct::Hcl(b.clone())) + .collect::>(), + _ => unimplemented!(), + } + } + + pub fn get_required_string_literal_from_attribute( + &self, + attribute_name: &str, + ) -> Result { + match &self { + Self::Hcl(block) => visit_required_string_literal_attribute(attribute_name, block), + _ => unimplemented!(), + } + } + + pub fn get_expression_from_attribute<'a>( + &'a self, + attribute_name: &str, + ) -> Option { + match &self { + Self::Hcl(block) => { + let Some(attribute) = block.body.get_attribute(attribute_name) else { + return None; + }; + Some(ConstructExpression::Hcl(attribute.value.clone())) + } + _ => unimplemented!(), + } + } + + // pub fn collect_constructs_referenced_by_construct( + // &self, + // input: Option<&T>, + // dependencies: &mut Vec<(Option<&T>, Expression)>, + // ) { + // for attribute in self.get_attributes() { + // let expr = attribute.get_value(); + // let mut references = vec![]; + // expr.collect_constructs_references_from_expression(input, &mut references); + // dependencies.append(&mut references); + // } + // for block in self.get_sub_constructs() { + // // block.coll + // // collect_constructs_referenced_by_construct(block, input, dependencies); + // } + // } + + pub fn get_span(&self) -> Option> { + match &self { + Self::Hcl(block) => block.body.span(), + _ => unimplemented!(), + } + } + + pub fn expect_hcl_block(&self) -> &Block { + let block = match &self { + Self::Hcl(src) => src, + _ => unimplemented!(), + }; + block + } } #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct RawHclContent(String); -impl RawHclContent { - pub fn from_string(s: String) -> Self { - RawHclContent(s) +pub enum RunbookSource { + Hcl(String), + Json(String), + Yaml(String), +} + +impl RunbookSource { + pub fn from_hcl_string(s: String) -> Self { + Self::Hcl(s) } + pub fn from_file_location(file_location: &FileLocation) -> Result { file_location .read_content_as_utf8() .map_err(|e| { Diagnostic::error_from_string(format!("{}", e.to_string())).location(&file_location) }) - .map(|s| RawHclContent(s)) + .map(|s| { + let res = match file_location.get_file_name() { + Some(name) if name.ends_with(".tx") => Self::Hcl(s), + Some(name) if name.ends_with(".tx.hcl") => Self::Hcl(s), + Some(name) if name.ends_with(".tx.yaml") => Self::Hcl(s), + Some(name) if name.ends_with(".tx.json") => Self::Hcl(s), + _ => { + return Err(Diagnostic::error_from_string(format!( + "file format unknown (.tx, .tx.hcl, .tx.yaml, .tx.json)", + )) + .location(&file_location)) + } + }; + Ok(res) + })? } - pub fn into_blocks(&self) -> Result, Diagnostic> { - let content = crate::hcl::parser::parse_body(&self.0).map_err(|e| { - Diagnostic::error_from_string(format!("parsing error: {}", e.to_string())) - })?; - Ok(content.into_blocks().into_iter().collect::>()) + pub fn into_constructs(&self) -> Result, Diagnostic> { + let constructs = match &self { + Self::Hcl(source) => { + let content = crate::hcl::parser::parse_body(&source).map_err(|e| { + Diagnostic::error_from_string(format!("parsing error: {}", e.to_string())) + })?; + content + .into_blocks() + .into_iter() + .map(RunbookConstruct::Hcl) + .collect::>() + } + _ => unimplemented!(), + }; + Ok(constructs) } - pub fn into_block_instance(&self) -> Result { - let mut blocks = self.into_blocks()?; + pub fn into_construct(&self) -> Result { + let mut blocks = self.into_constructs()?; if blocks.len() != 1 { return Err(Diagnostic::error_from_string( "expected exactly one block instance".into(), @@ -251,18 +616,23 @@ impl RawHclContent { Ok(blocks.pop_front().unwrap()) } - pub fn to_bytes(&self) -> Result, Diagnostic> { - let mut bytes = vec![0u8; 2 * self.0.len()]; - crate::hex::encode_to_slice(self.0.clone(), &mut bytes).map_err(|e| { - Diagnostic::error_from_string(format!("failed to encode raw content: {e}")) - })?; - Ok(bytes) - } - pub fn to_string(&self) -> String { - self.0.clone() + // pub fn to_bytes(&self) -> Result, Diagnostic> { + // let mut bytes = vec![0u8; 2 * self.0.len()]; + // crate::hex::encode_to_slice(self.0.clone(), &mut bytes).map_err(|e| { + // Diagnostic::error_from_string(format!("failed to encode raw content: {e}")) + // })?; + // Ok(bytes) + // } + pub fn as_hcl_str(&self) -> &str { + let source = match &self { + Self::Hcl(src) => src, + _ => unreachable!(), + }; + source.as_str() } - pub fn from_block(block: &Block) -> Self { - RawHclContent::from_string( + + pub fn from_hcl_construct(block: &Block) -> Self { + Self::from_hcl_string( Body::builder().block(block.clone()).build().to_string().trim().to_string(), ) } @@ -321,21 +691,29 @@ mod tests { "# ); - let raw_hcl = RawHclContent::from_string(input.trim().to_string()); - let blocks = raw_hcl.into_blocks().unwrap(); - assert_eq!(blocks.len(), 4); - let addon_block = RawHclContent::from_block(&blocks[0]).to_string(); + let raw_hcl = RunbookSource::from_hcl_string(input.trim().to_string()); + let constructs = raw_hcl.into_constructs().unwrap(); + assert_eq!(constructs.len(), 4); + let addon_block = RunbookSource::from_hcl_construct(&constructs[0].expect_hcl_block()) + .as_hcl_str() + .to_string(); assert_eq!(addon_block, addon_block_str); - let signer_block = RawHclContent::from_block(&blocks[1]).to_string(); + let signer_block = RunbookSource::from_hcl_construct(&constructs[1].expect_hcl_block()) + .as_hcl_str() + .to_string(); assert_eq!(signer_block, signer_block_str); - let runbook_block = RawHclContent::from_block(&blocks[2]).to_string(); + let runbook_block = RunbookSource::from_hcl_construct(&constructs[2].expect_hcl_block()) + .as_hcl_str() + .to_string(); assert_eq!(runbook_block, runbook_block_str); - let output_block = RawHclContent::from_block(&blocks[3]).to_string(); + let output_block = RunbookSource::from_hcl_construct(&constructs[3].expect_hcl_block()) + .as_hcl_str() + .to_string(); assert_eq!(output_block, output_block_str); } #[test] - fn test_collect_constructs_references_from_block() { + fn test_collect_constructs_referenced_by_construct() { let input = r#" runbook "test" { location = "./embedded-runbook.json" @@ -352,10 +730,15 @@ mod tests { } "#; - let raw_hcl = RawHclContent::from_string(input.trim().to_string()); - let block = raw_hcl.into_block_instance().unwrap(); + let raw_hcl = RunbookSource::from_hcl_string(input.trim().to_string()); + let construct = raw_hcl.into_construct().unwrap(); + let mut dependencies = vec![]; - collect_constructs_references_from_block(&block, None::<&CommandInput>, &mut dependencies); + collect_constructs_referenced_by_construct( + &construct, + None::<&CommandInput>, + &mut dependencies, + ); assert_eq!(dependencies.len(), 7); } @@ -378,12 +761,12 @@ mod tests { } "#; - let raw_hcl = RawHclContent::from_string(input.trim().to_string()); - let block = raw_hcl.into_block_instance().unwrap(); + let raw_hcl = RunbookSource::from_hcl_string(input.trim().to_string()); + let block = raw_hcl.into_construct().unwrap().expect_hcl_block().clone(); let attribute = block.body.get_attribute("chain_id").unwrap(); let mut dependencies = vec![]; - collect_constructs_references_from_expression( + collect_constructs_references_from_hcl_expression( &attribute.value, None::<&CommandInput>, &mut dependencies, diff --git a/crates/txtx-addon-kit/src/types/commands.rs b/crates/txtx-addon-kit/src/types/commands.rs index f45bce059..8ae17a6b0 100644 --- a/crates/txtx-addon-kit/src/types/commands.rs +++ b/crates/txtx-addon-kit/src/types/commands.rs @@ -1,3 +1,4 @@ +use indexmap::IndexMap; use serde::{ ser::{SerializeMap, SerializeStruct}, Serialize, Serializer, @@ -10,16 +11,11 @@ use std::{ }; use uuid::Uuid; -use hcl_edit::{expr::Expression, structure::Block, Span}; -use indexmap::IndexMap; - +use crate::types::stores::ValueStore; use crate::{ constants::{SIGNED_MESSAGE_BYTES, SIGNED_TRANSACTION_BYTES}, - helpers::hcl::{ - collect_constructs_references_from_expression, visit_optional_untyped_attribute, - }, + helpers::hcl::{ConstructExpression, ConstructExpressionRef, RunbookConstruct}, }; -use crate::{helpers::hcl::get_object_expression_key, types::stores::ValueStore}; use super::{ cloud_interface::CloudServiceContext, @@ -603,7 +599,7 @@ impl CommandInstanceType { pub struct CommandInstance { pub specification: CommandSpecification, pub name: String, - pub block: Block, + pub construct: RunbookConstruct, pub package_id: PackageId, pub namespace: String, pub typing: CommandInstanceType, @@ -632,26 +628,22 @@ impl WithEvaluatableInputs for CommandInstance { fn name(&self) -> String { self.name.clone() } - fn block(&self) -> &Block { - &self.block - } - /// Checks the `CommandInstance` HCL Block for an attribute named `input.name` - fn get_expression_from_input(&self, input_name: &str) -> Option { - visit_optional_untyped_attribute(&input_name, &self.block) + fn construct(&self) -> &RunbookConstruct { + &self.construct } - fn get_blocks_for_map( - &self, + fn get_blocks_for_map<'a>( + &'a self, input_name: &str, input_typing: &Type, input_optional: bool, - ) -> Result>, Vec> { + ) -> Result>, Vec> { let mut entries = vec![]; match &input_typing { Type::Map(_) => { - for block in self.block.body.get_blocks(&input_name) { - entries.push(block.clone()); + for object in self.construct.get_sub_constructs_type(&input_name) { + entries.push(object.into()); } } _ => { @@ -671,21 +663,13 @@ impl WithEvaluatableInputs for CommandInstance { Ok(Some(entries)) } - fn get_expression_from_block( - &self, - block: &Block, - prop: &ObjectProperty, - ) -> Option { - visit_optional_untyped_attribute(&prop.name, &block) - } - fn get_expression_from_object( &self, input_name: &str, input_typing: &Type, - ) -> Result, Vec> { + ) -> Result, Vec> { match &input_typing { - Type::Object(_) => Ok(visit_optional_untyped_attribute(&input_name, &self.block)), + Type::Object(_) => Ok(self.construct.get_expression_from_attribute(input_name)), _ => Err(vec![Diagnostic::error_from_string(format!( "command '{}' (type '{}') expected object for input '{}'", self.name, self.specification.matcher, input_name @@ -697,17 +681,10 @@ impl WithEvaluatableInputs for CommandInstance { &self, input_name: &str, prop: &ObjectProperty, - ) -> Option { - let expr = visit_optional_untyped_attribute(&input_name, &self.block); + ) -> Option { + let expr = self.construct.get_expression_from_attribute(input_name); match expr { - Some(expr) => { - let object_expr = expr.as_object().unwrap(); - let expr_res = get_object_expression_key(object_expr, &prop.name); - match expr_res { - Some(expression) => Some(expression.expr().clone()), - None => None, - } - } + Some(expr) => expr.get_object_expression_key(&prop.name), None => None, } } @@ -728,10 +705,10 @@ impl CommandInstance { } pub fn get_group(&self) -> String { - let Some(group) = self.block.body.get_attribute("group") else { - return format!("{} Review", self.specification.name.to_string()); - }; - group.value.to_string() + match self.construct.get_attribute_stringified("group") { + Some(entry) => entry, + None => format!("{} Review", self.specification.name.to_string()), + } } pub fn check_executability( @@ -846,7 +823,7 @@ impl CommandInstance { let spec = &self.specification; let res = (spec.run_execution)(&construct_did, &self.specification, &values, progress_tx)? .await - .map_err(|e| e.set_span_range(self.block.span())); + .map_err(|e| e.set_span_range(self.construct.get_span())); for request in action_item_requests.iter_mut() { let (status, success) = match &res { @@ -905,7 +882,7 @@ impl CommandInstance { signer_instances, signers, ); - return consolidate_nested_execution_result(future, self.block.span()).await; + return consolidate_nested_execution_result(future, self.construct.get_span()).await; } pub fn prepare_nested_execution( @@ -1002,7 +979,7 @@ impl CommandInstance { signers, ); let (signer_state, mut actions) = - consolidate_signer_future_result(future, self.block.span()).await?; + consolidate_signer_future_result(future, self.construct.get_span()).await?; consolidated_actions.append(&mut actions); consolidated_actions.filter_existing_action_items(action_item_requests); Ok((signer_state, consolidated_actions)) @@ -1033,7 +1010,8 @@ impl CommandInstance { signer_instances, signers, ); - let res = consolidate_signer_activate_future_result(future, self.block.span()).await?; + let res = + consolidate_signer_activate_future_result(future, self.construct.get_span()).await?; for request in action_item_requests.iter_mut() { let (status, success) = match &res { @@ -1129,8 +1107,8 @@ impl CommandInstance { } impl ConstructInstance for CommandInstance { - fn block(&self) -> &Block { - &self.block + fn construct(&self) -> &RunbookConstruct { + &self.construct } fn inputs(&self) -> Vec<&impl EvaluatableInput> { self.specification.inputs.iter().chain(&self.specification.default_inputs).collect() @@ -1142,7 +1120,7 @@ impl ConstructInstance for CommandInstance { pub trait ConstructInstance { /// The HCL block of the construct - fn block(&self) -> &Block; + fn construct(&self) -> &RunbookConstruct; fn inputs(&self) -> Vec<&impl EvaluatableInput>; fn accepts_arbitrary_inputs(&self) -> bool { false @@ -1150,27 +1128,27 @@ pub trait ConstructInstance { fn get_expressions_referencing_commands_from_inputs( &self, - ) -> Vec<(Option<&impl EvaluatableInput>, Expression)> { + ) -> Vec<(Option, ConstructExpression)> { let mut expressions = vec![]; for input in self.inputs() { input.typing().get_expressions_referencing_constructs( - &self.block(), + &self.construct(), + input.name().as_str(), input, &mut expressions, ); } if self.accepts_arbitrary_inputs() { - for attribute in self.block().body.attributes() { + for attribute in self.construct().get_attributes() { let mut references = vec![]; - collect_constructs_references_from_expression( - &attribute.value, - None, - &mut references, - ); + attribute + .get_value() + .collect_constructs_references_from_expression(None, &mut references); expressions.append(&mut references); } } - expressions + // expressions + vec![] } } diff --git a/crates/txtx-addon-kit/src/types/embedded_runbooks/mod.rs b/crates/txtx-addon-kit/src/types/embedded_runbooks/mod.rs index b953caf80..6c536cbd6 100644 --- a/crates/txtx-addon-kit/src/types/embedded_runbooks/mod.rs +++ b/crates/txtx-addon-kit/src/types/embedded_runbooks/mod.rs @@ -1,8 +1,6 @@ use std::collections::{HashMap, HashSet}; -use hcl_edit::{expr::Expression, structure::Block}; - -use crate::helpers::hcl::{get_object_expression_key, visit_optional_untyped_attribute}; +use crate::helpers::hcl::{ConstructExpression, RunbookConstruct}; use super::{ commands::{CommandInput, CommandInstance, ConstructInstance}, @@ -10,7 +8,7 @@ use super::{ package::Package, signers::{SignerInstance, SignersState}, stores::ValueStore, - types::{ObjectProperty, Type}, + types::Type, AddonInstance, ConstructDid, ConstructId, EvaluatableInput, PackageId, RunbookId, WithEvaluatableInputs, }; @@ -18,7 +16,7 @@ use super::{ #[derive(Debug, Clone)] pub struct EmbeddedRunbookInstance { pub name: String, - pub block: Block, + pub construct: RunbookConstruct, pub package_id: PackageId, pub specification: EmbeddedRunbookInstanceSpecification, } @@ -27,12 +25,8 @@ impl WithEvaluatableInputs for EmbeddedRunbookInstance { fn name(&self) -> String { self.name.clone() } - fn block(&self) -> &Block { - &self.block - } - - fn get_expression_from_input(&self, input_name: &str) -> Option { - visit_optional_untyped_attribute(&input_name, &self.block) + fn construct(&self) -> &RunbookConstruct { + &self.construct } fn get_blocks_for_map( @@ -40,13 +34,13 @@ impl WithEvaluatableInputs for EmbeddedRunbookInstance { input_name: &str, input_typing: &Type, input_optional: bool, - ) -> Result>, Vec> { + ) -> Result>, Vec> { let mut entries = vec![]; match &input_typing { Type::Map(_) => { - for block in self.block.body.get_blocks(&input_name) { - entries.push(block.clone()); + for block in self.construct.get_sub_constructs_type(input_name) { + entries.push(block.into()); } } _ => { @@ -66,21 +60,13 @@ impl WithEvaluatableInputs for EmbeddedRunbookInstance { Ok(Some(entries)) } - fn get_expression_from_block( - &self, - block: &Block, - prop: &ObjectProperty, - ) -> Option { - visit_optional_untyped_attribute(&prop.name, &block) - } - fn get_expression_from_object( &self, input_name: &str, input_typing: &Type, - ) -> Result, Vec> { + ) -> Result, Vec> { match &input_typing { - Type::Object(_) => Ok(visit_optional_untyped_attribute(&input_name, &self.block)), + Type::Object(_) => Ok(self.construct.get_expression_from_attribute(input_name)), _ => Err(vec![Diagnostic::error_from_string(format!( "embedded runbook '{}' expected object for input '{}'", self.name, input_name @@ -92,17 +78,10 @@ impl WithEvaluatableInputs for EmbeddedRunbookInstance { &self, input_name: &str, prop: &super::types::ObjectProperty, - ) -> Option { - let expr = visit_optional_untyped_attribute(&input_name, &self.block); + ) -> Option { + let expr = self.construct.get_expression_from_attribute(&input_name); match expr { - Some(expr) => { - let object_expr = expr.as_object().unwrap(); - let expr_res = get_object_expression_key(object_expr, &prop.name); - match expr_res { - Some(expression) => Some(expression.expr().clone()), - None => None, - } - } + Some(expr) => expr.get_object_expression_key(&prop.name), None => None, } } @@ -115,13 +94,13 @@ impl WithEvaluatableInputs for EmbeddedRunbookInstance { impl EmbeddedRunbookInstance { pub fn new( name: &str, - block: &Block, + construct: &RunbookConstruct, package_id: &PackageId, specification: EmbeddedRunbookInstanceSpecification, ) -> Self { Self { name: name.to_string(), - block: block.clone(), + construct: construct.clone(), package_id: package_id.clone(), specification, } @@ -129,8 +108,8 @@ impl EmbeddedRunbookInstance { } impl ConstructInstance for EmbeddedRunbookInstance { - fn block(&self) -> &Block { - &self.block + fn construct(&self) -> &RunbookConstruct { + &self.construct } fn inputs(&self) -> Vec<&impl EvaluatableInput> { diff --git a/crates/txtx-addon-kit/src/types/mod.rs b/crates/txtx-addon-kit/src/types/mod.rs index 2005ed548..0ea76f22a 100644 --- a/crates/txtx-addon-kit/src/types/mod.rs +++ b/crates/txtx-addon-kit/src/types/mod.rs @@ -3,14 +3,13 @@ use std::fmt::Display; use std::path::Path; use diagnostics::Diagnostic; -use hcl_edit::expr::Expression; -use hcl_edit::structure::Block; use serde::de::Error; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use sha2::{Digest, Sha256}; use types::{ObjectDefinition, ObjectProperty, Type}; use crate::helpers::fs::FileLocation; +use crate::helpers::hcl::{ConstructExpression, RunbookConstruct}; pub mod block_id; pub mod cloud_interface; @@ -326,31 +325,28 @@ impl AddonPostProcessingResult { pub struct AddonInstance { pub addon_id: String, pub package_id: PackageId, - pub block: Block, + pub construct: RunbookConstruct, } pub trait WithEvaluatableInputs { fn name(&self) -> String; - fn block(&self) -> &Block; - fn get_expression_from_input(&self, input_name: &str) -> Option; + fn construct(&self) -> &RunbookConstruct; fn get_blocks_for_map( &self, input_name: &str, input_typing: &Type, input_optional: bool, - ) -> Result>, Vec>; - fn get_expression_from_block(&self, block: &Block, prop: &ObjectProperty) - -> Option; + ) -> Result>, Vec>; fn get_expression_from_object( &self, input_name: &str, input_typing: &Type, - ) -> Result, Vec>; + ) -> Result, Vec>; fn get_expression_from_object_property( &self, input_name: &str, prop: &ObjectProperty, - ) -> Option; + ) -> Option; fn spec_inputs(&self) -> Vec; } diff --git a/crates/txtx-addon-kit/src/types/signers.rs b/crates/txtx-addon-kit/src/types/signers.rs index 32fb7fc91..257799df4 100644 --- a/crates/txtx-addon-kit/src/types/signers.rs +++ b/crates/txtx-addon-kit/src/types/signers.rs @@ -2,10 +2,11 @@ use crate::constants::{ ACTION_ITEM_CHECK_ADDRESS, ACTION_ITEM_CHECK_BALANCE, CHECKED_ADDRESS, IS_BALANCE_CHECKED, PROVIDE_PUBLIC_KEY_ACTION_RESULT, }; -use crate::helpers::hcl::visit_optional_untyped_attribute; +use crate::helpers::hcl::{ + visit_optional_untyped_attribute, ConstructExpression, ConstructExpressionRef, RunbookConstruct, +}; use crate::types::stores::ValueStore; use futures::future; -use hcl_edit::{expr::Expression, structure::Block, Span}; use std::{collections::HashMap, future::Future, pin::Pin}; use super::commands::ConstructInstance; @@ -308,7 +309,7 @@ pub struct SignerSpecification { pub struct SignerInstance { pub specification: SignerSpecification, pub name: String, - pub block: Block, + pub construct: RunbookConstruct, pub package_id: PackageId, pub namespace: String, } @@ -326,12 +327,12 @@ impl SignerInstance { } /// Checks the `CommandInstance` HCL Block for an attribute named `input.name` - pub fn get_expression_from_input(&self, input: &CommandInput) -> Option { - visit_optional_untyped_attribute(&input.name, &self.block) + pub fn get_expression_from_input(&self, input: &CommandInput) -> Option { + self.construct.get_expression_from_attribute(&input.name) } pub fn get_group(&self) -> String { - let Some(group) = self.block.body.get_attribute("group") else { + let Some(group) = self.construct.expect_hcl_block().body.get_attribute("group") else { return format!("{} Review", self.specification.name.to_string()); }; group.value.to_string() @@ -341,13 +342,13 @@ impl SignerInstance { &self, input: &CommandInput, prop: &ObjectProperty, - ) -> Option { - let object = self.block.body.get_blocks(&input.name).next(); - match object { - Some(block) => { - let expr_res = visit_optional_untyped_attribute(&prop.name, &block); + ) -> Option { + let sub_constructs = self.construct.get_sub_constructs_type(&input.name); + match sub_constructs.first() { + Some(construct) => { + let expr_res = construct.get_expression_from_attribute(&prop.name); match expr_res { - Some(expression) => Some(expression), + Some(expression) => Some(expression.into()), None => None, } } @@ -432,7 +433,7 @@ impl SignerInstance { is_public_key_required, ); - consolidate_signer_future_result(res, self.block.span()).await + consolidate_signer_future_result(res, self.construct.get_span()).await } pub async fn perform_activation( @@ -457,13 +458,13 @@ impl SignerInstance { signers_instances, progress_tx, ); - consolidate_signer_activate_future_result(future, self.block.span()).await? + consolidate_signer_activate_future_result(future, self.construct.get_span()).await? } } impl ConstructInstance for SignerInstance { - fn block(&self) -> &Block { - &self.block + fn construct(&self) -> &RunbookConstruct { + &self.construct } fn inputs(&self) -> Vec<&impl EvaluatableInput> { self.specification.inputs.iter().chain(&self.specification.default_inputs).collect() diff --git a/crates/txtx-addon-kit/src/types/types.rs b/crates/txtx-addon-kit/src/types/types.rs index b1651b009..43a3fa9a2 100644 --- a/crates/txtx-addon-kit/src/types/types.rs +++ b/crates/txtx-addon-kit/src/types/types.rs @@ -1,5 +1,4 @@ use hcl_edit::expr::Expression; -use hcl_edit::structure::Block; use indexmap::IndexMap; use jaq_interpret::Val; use serde::de::{self, MapAccess, Visitor}; @@ -9,10 +8,7 @@ use serde_json::{Map, Value as JsonValue}; use std::collections::VecDeque; use std::fmt::{self, Debug}; -use crate::helpers::hcl::{ - collect_constructs_references_from_block, collect_constructs_references_from_expression, - visit_optional_untyped_attribute, -}; +use crate::helpers::hcl::{collect_constructs_referenced_by_construct, RunbookConstruct}; use super::diagnostics::Diagnostic; use super::{Did, EvaluatableInput}; @@ -935,20 +931,19 @@ impl Type { /// need to look for nested blocks and properties. pub fn get_expressions_referencing_constructs<'a, T: EvaluatableInput>( &self, - block: &Block, + construct: &RunbookConstruct, + input_name: &str, input: &'a T, dependencies: &mut Vec<(Option<&'a T>, Expression)>, ) { - let input_name = input.name(); match self { Type::Map(ref object_def) => match object_def { ObjectDefinition::Strict(props) => { - for block in block.body.get_blocks(&input_name) { + for construct in construct.get_sub_constructs_type(&input_name) { for prop in props.iter() { - let res = visit_optional_untyped_attribute(&prop.name, &block); + let res = construct.get_expression_from_attribute(&prop.name); if let Some(expr) = res { - collect_constructs_references_from_expression( - &expr, + expr.collect_constructs_references_from_expression( Some(input), dependencies, ); @@ -957,24 +952,26 @@ impl Type { } } ObjectDefinition::Arbitrary(_) => { - for block in block.body.get_blocks(&input_name) { - collect_constructs_references_from_block(block, Some(input), dependencies); + for sub_construct in construct.get_sub_constructs_type(&input_name) { + collect_constructs_referenced_by_construct( + &sub_construct, + Some(input), + dependencies, + ); } } }, Type::Object(ref object_def) => { - if let Some(expr) = visit_optional_untyped_attribute(&input_name, &block) { - collect_constructs_references_from_expression(&expr, Some(input), dependencies); + if let Some(expr) = construct.get_expression_from_attribute(&input_name) { + expr.collect_constructs_references_from_expression(Some(input), dependencies); } match object_def { ObjectDefinition::Strict(props) => { for prop in props.iter() { - for block in block.body.get_blocks(&input_name) { - if let Some(expr) = - visit_optional_untyped_attribute(&prop.name, &block) + for object in construct.get_sub_constructs_type(&input_name) { + if let Some(expr) = object.get_expression_from_attribute(&prop.name) { - collect_constructs_references_from_expression( - &expr, + expr.collect_constructs_references_from_expression( Some(input), dependencies, ); @@ -983,9 +980,9 @@ impl Type { } } ObjectDefinition::Arbitrary(_) => { - for block in block.body.get_blocks(&input_name) { - collect_constructs_references_from_block( - block, + for object in construct.get_sub_constructs_type(&input_name) { + collect_constructs_referenced_by_construct( + &object, Some(input), dependencies, ); @@ -994,8 +991,8 @@ impl Type { } } _ => { - if let Some(expr) = visit_optional_untyped_attribute(&input_name, &block) { - collect_constructs_references_from_expression(&expr, Some(input), dependencies); + if let Some(expr) = construct.get_expression_from_attribute(&input_name) { + expr.collect_constructs_references_from_expression(Some(input), dependencies); } } } diff --git a/crates/txtx-cloud/src/login.rs b/crates/txtx-cloud/src/login.rs index cd17d517c..739039613 100644 --- a/crates/txtx-cloud/src/login.rs +++ b/crates/txtx-cloud/src/login.rs @@ -155,11 +155,7 @@ pub async fn handle_login_command( if auth_config.is_access_token_expired() { match auth_config.refresh_session(id_service_url, &auth_config.pat).await { Ok(auth_config) => { - println!( - "{} Logged in as {}.", - green!("✓"), - auth_config.user.display_name - ); + println!("{} Logged in as {}.", green!("✓"), auth_config.user.display_name); return Ok(()); } Err(_e) => { diff --git a/crates/txtx-cloud/src/workspace.rs b/crates/txtx-cloud/src/workspace.rs index c4e50315b..6e7ab591e 100644 --- a/crates/txtx-cloud/src/workspace.rs +++ b/crates/txtx-cloud/src/workspace.rs @@ -2,7 +2,7 @@ use serde::Deserialize; use serde_json::json; use txtx_addon_kit::{reqwest, uuid::Uuid}; -pub async fn get_user_workspaces( +pub async fn fetch_workspaces( access_token: &str, service_gql_url: &str, ) -> Result, String> { diff --git a/crates/txtx-core/src/eval/mod.rs b/crates/txtx-core/src/eval/mod.rs index 24dde1a98..0d74c9103 100644 --- a/crates/txtx-core/src/eval/mod.rs +++ b/crates/txtx-core/src/eval/mod.rs @@ -4,6 +4,7 @@ use crate::runbook::{ RuntimeContext, }; use crate::types::{RunbookExecutionContext, RunbookSources}; +use kit::helpers::hcl::ConstructExpression; use kit::types::commands::ConstructInstance; use kit::types::types::ObjectDefinition; use std::collections::{BTreeMap, HashMap, HashSet}; @@ -970,7 +971,7 @@ pub enum ExpressionEvaluationStatus { } pub fn eval_expression( - expr: &Expression, + expr: &ConstructExpression, dependencies_execution_results: &DependencyExecutionResultCache, package_id: &PackageId, runbook_workspace_context: &RunbookWorkspaceContext, diff --git a/crates/txtx-core/src/lib.rs b/crates/txtx-core/src/lib.rs index 798e72dac..4c45b3db0 100644 --- a/crates/txtx-core/src/lib.rs +++ b/crates/txtx-core/src/lib.rs @@ -816,7 +816,7 @@ pub async fn process_background_tasks( if let Some(command_instance) = flow_context.execution_context.commands_instances.get_mut(&construct_did) { - diag = diag.set_span_range(command_instance.block.span()); + diag = diag.set_span_range(command_instance.construct.get_span()); }; if let Some(SupervisedBackgroundTaskContext { block_tx, diff --git a/crates/txtx-core/src/runbook/embedded_runbook/mod.rs b/crates/txtx-core/src/runbook/embedded_runbook/mod.rs index df8463e16..c8ebd3439 100644 --- a/crates/txtx-core/src/runbook/embedded_runbook/mod.rs +++ b/crates/txtx-core/src/runbook/embedded_runbook/mod.rs @@ -1,5 +1,6 @@ pub mod publishable; +use kit::helpers::hcl::RunbookConstruct; use publishable::PublishableEmbeddedRunbookSpecification; use std::collections::HashMap; use txtx_addon_kit::hcl::structure::Block; @@ -182,7 +183,7 @@ impl EmbeddingRunbookContext { let defaults = runtime_context .generate_addon_defaults_from_block( existing_addon_defaults, - &addon_instance.block, + &addon_instance.construct, &addon_instance.addon_id, &addon_instance.package_id, &DependencyExecutionResultCache::new(), @@ -220,7 +221,7 @@ impl EmbeddedRunbookInstanceBuilder { embedded_runbook_location: FileLocation, embedded_runbook_name: &str, package_id: &PackageId, - block: &Block, + construct: &RunbookConstruct, addons_context: &mut AddonsContext, ) -> Result { let bytes = embedded_runbook_location.read_content().map_err(|e| { @@ -240,7 +241,7 @@ impl EmbeddedRunbookInstanceBuilder { let spec = publishable_runbook_instance_specification .into_embedded_runbook_instance_specification(addons_context)?; - Ok(EmbeddedRunbookInstance::new(embedded_runbook_name, block, package_id, spec)) + Ok(EmbeddedRunbookInstance::new(embedded_runbook_name, construct, package_id, spec)) } } @@ -249,7 +250,7 @@ mod tests { use std::collections::HashSet; use txtx_addon_kit::helpers::fs::FileLocation; - use txtx_addon_kit::helpers::hcl::RawHclContent; + use txtx_addon_kit::helpers::hcl::RunbookSource; use txtx_addon_kit::types::commands::CommandInstanceType; use txtx_addon_kit::types::embedded_runbooks::EmbeddedRunbookInputSpecification; use txtx_addon_kit::types::embedded_runbooks::EmbeddedRunbookValueInputSpecification; @@ -293,14 +294,14 @@ mod tests { namespace: "std".to_string(), typing: CommandInstanceType::Variable, name: my_var_name.to_string(), - hcl: RawHclContent::from_string(variable_hcl.into()), + hcl: RunbookSource::from_hcl_string(variable_hcl.into()), }; let my_output_inst = PublishableCommandInstance { package_id: package_id.clone(), namespace: "std".to_string(), typing: CommandInstanceType::Output, name: my_output_name.to_string(), - hcl: RawHclContent::from_string(output_hcl.into()), + hcl: RunbookSource::from_hcl_string(output_hcl.into()), }; let mut package = Package::new(&package_id); diff --git a/crates/txtx-core/src/runbook/embedded_runbook/publishable.rs b/crates/txtx-core/src/runbook/embedded_runbook/publishable.rs index 6996fb97e..757a23fac 100644 --- a/crates/txtx-core/src/runbook/embedded_runbook/publishable.rs +++ b/crates/txtx-core/src/runbook/embedded_runbook/publishable.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use serde_with::serde_as; use std::collections::{HashMap, HashSet}; -use txtx_addon_kit::helpers::hcl::RawHclContent; +use txtx_addon_kit::helpers::hcl::RunbookSource; use txtx_addon_kit::types::commands::{CommandInstance, CommandInstanceType}; use txtx_addon_kit::types::diagnostics::Diagnostic; use txtx_addon_kit::types::embedded_runbooks::EmbeddedRunbookInstance; @@ -314,24 +314,24 @@ impl PublishableWorkspaceContext { pub struct PublishableAddonInstance { pub package_id: PackageId, pub addon_id: String, - pub hcl: RawHclContent, + pub hcl: RunbookSource, } impl PublishableAddonInstance { pub fn into_addon_instance(self) -> Result { - let block = self.hcl.into_block_instance().map_err(|e| { + let construct = self.hcl.into_construct().map_err(|e| { Diagnostic::error_from_string(format!( "unable to parse hcl content for embedded runbook instance: {}", e.message )) })?; - Ok(AddonInstance { package_id: self.package_id, addon_id: self.addon_id, block }) + Ok(AddonInstance { package_id: self.package_id, addon_id: self.addon_id, construct }) } pub fn from_addon_instance(addon_instance: &AddonInstance) -> Self { Self { package_id: addon_instance.package_id.clone(), addon_id: addon_instance.addon_id.clone(), - hcl: RawHclContent::from_block(&addon_instance.block), + hcl: RunbookSource::from_hcl_construct(&addon_instance.construct), } } } @@ -350,7 +350,7 @@ pub struct PublishableEmbeddedRunbookInstance { pub instance_name: String, pub package_id: PackageId, pub specification: PublishableEmbeddedRunbookSpecification, - pub hcl: RawHclContent, + pub hcl: RunbookSource, } impl PublishableEmbeddedRunbookInstance { @@ -358,7 +358,7 @@ impl PublishableEmbeddedRunbookInstance { self, addons_context: &mut AddonsContext, ) -> Result { - let block = self.hcl.into_block_instance().map_err(|e| { + let construct = self.hcl.into_construct().map_err(|e| { Diagnostic::error_from_string(format!( "unable to parse hcl content for embedded runbook instance: {}", e.message @@ -370,7 +370,7 @@ impl PublishableEmbeddedRunbookInstance { specification: self .specification .into_embedded_runbook_instance_specification(addons_context)?, - block, + construct, }) } pub fn from_embedded_runbook_instance(instance: &EmbeddedRunbookInstance) -> Self { @@ -378,7 +378,7 @@ impl PublishableEmbeddedRunbookInstance { instance_name: instance.name.clone(), package_id: instance.package_id.clone(), specification: PublishableEmbeddedRunbookSpecification::from_embedded_runbook_instance_specification(&instance.specification), - hcl: RawHclContent::from_block(&instance.block), + hcl: RunbookSource::from_hcl_construct(&instance.construct), } } } @@ -389,7 +389,7 @@ pub struct PublishableCommandInstance { pub namespace: String, pub typing: CommandInstanceType, pub name: String, - pub hcl: RawHclContent, + pub hcl: RunbookSource, } impl PublishableCommandInstance { @@ -397,7 +397,7 @@ impl PublishableCommandInstance { self, addons_context: &mut AddonsContext, ) -> Result { - let block = self.hcl.into_block_instance().map_err(|e| { + let construct = self.hcl.into_construct().map_err(|e| { Diagnostic::error_from_string(format!( "unable to parse hcl content for embedded runbook instance: {}", e.message @@ -407,7 +407,7 @@ impl PublishableCommandInstance { CommandInstanceType::Variable => CommandInstance { specification: commands::new_variable_specification(), name: self.name.clone(), - block: block.clone(), + construct: construct.clone(), package_id: self.package_id.clone(), namespace: self.namespace.clone(), typing: CommandInstanceType::Variable, @@ -415,7 +415,7 @@ impl PublishableCommandInstance { CommandInstanceType::Output => CommandInstance { specification: commands::new_output_specification(), name: self.name.clone(), - block: block.clone(), + construct: construct.clone(), package_id: self.package_id.clone(), namespace: self.namespace.clone(), typing: CommandInstanceType::Output, @@ -436,7 +436,7 @@ impl PublishableCommandInstance { &command_id, &self.name, &self.package_id, - &block, + &construct, &self.package_id.package_location, ) .map_err(|diag| { @@ -450,7 +450,7 @@ impl PublishableCommandInstance { CommandInstanceType::Module => CommandInstance { specification: commands::new_module_specification(), name: self.name.clone(), - block: block.clone(), + construct: construct.clone(), package_id: self.package_id.clone(), namespace: self.namespace.clone(), typing: CommandInstanceType::Module, @@ -466,7 +466,7 @@ impl PublishableCommandInstance { namespace: command_instance.namespace.clone(), typing: command_instance.typing.clone(), name: command_instance.name.clone(), - hcl: RawHclContent::from_block(&command_instance.block), + hcl: RunbookSource::from_hcl_construct(&command_instance.construct), } } } diff --git a/crates/txtx-core/src/runbook/execution_context.rs b/crates/txtx-core/src/runbook/execution_context.rs index 2241f6fbe..7bd117ea7 100644 --- a/crates/txtx-core/src/runbook/execution_context.rs +++ b/crates/txtx-core/src/runbook/execution_context.rs @@ -630,7 +630,7 @@ impl RunbookExecutionContext { .await .map_err(|d| { d.location(&construct_id.construct_location) - .set_span_range(command_instance.block.span()) + .set_span_range(command_instance.construct.get_span()) })?; self.commands_inputs_evaluation_results diff --git a/crates/txtx-core/src/runbook/flow_context.rs b/crates/txtx-core/src/runbook/flow_context.rs index eb12cc9ee..5a0dbd247 100644 --- a/crates/txtx-core/src/runbook/flow_context.rs +++ b/crates/txtx-core/src/runbook/flow_context.rs @@ -1,3 +1,4 @@ +use kit::helpers::hcl::ConstructAttributeRef; use txtx_addon_kit::hcl::structure::Attribute; use txtx_addon_kit::indexmap::IndexMap; use txtx_addon_kit::types::commands::{CommandExecutionResult, DependencyExecutionResultCache}; @@ -66,7 +67,7 @@ impl FlowContext { pub fn index_flow_inputs_from_attributes( &mut self, - attributes: &Vec, + attributes: &Vec, dependencies_execution_results: &DependencyExecutionResultCache, package_id: &PackageId, workspace_context: &RunbookWorkspaceContext, @@ -75,7 +76,7 @@ impl FlowContext { ) -> Result<(), Diagnostic> { for attr in attributes.into_iter() { let res = eval::eval_expression( - &attr.value, + &attr.get_value(), &dependencies_execution_results, &package_id, &workspace_context, diff --git a/crates/txtx-core/src/runbook/graph_context.rs b/crates/txtx-core/src/runbook/graph_context.rs index f2eeadb0f..b6b241da8 100644 --- a/crates/txtx-core/src/runbook/graph_context.rs +++ b/crates/txtx-core/src/runbook/graph_context.rs @@ -82,7 +82,7 @@ impl RunbookGraphContext { command_instance.name, ) .location(&construct_id.construct_location) - .set_span_range(command_instance.block.span()), + .set_span_range(command_instance.construct.get_span()), ); } } @@ -108,7 +108,7 @@ impl RunbookGraphContext { command_instance.name, ) .location(&construct_id.construct_location) - .set_span_range(command_instance.block.span()), + .set_span_range(command_instance.construct.get_span()), ); } } @@ -134,7 +134,7 @@ impl RunbookGraphContext { command_instance.name, ) .location(&construct_id.construct_location) - .set_span_range(command_instance.block.span()), + .set_span_range(command_instance.construct.get_span()), ); } } @@ -176,7 +176,7 @@ impl RunbookGraphContext { command_instance.name, ) .location(&construct_id.construct_location) - .set_span_range(command_instance.block.span()), + .set_span_range(command_instance.construct.get_span()), ); } } @@ -218,7 +218,7 @@ impl RunbookGraphContext { embedded_runbook_instance.name, ) .location(&construct_id.construct_location) - .set_span_range(embedded_runbook_instance.block.span()), + .set_span_range(embedded_runbook_instance.construct.get_span()), ); } } @@ -252,7 +252,7 @@ impl RunbookGraphContext { signer_instance.name, ) .location(&construct_id.construct_location) - .set_span_range(signer_instance.block.span()), + .set_span_range(signer_instance.construct.get_span()), ); } } diff --git a/crates/txtx-core/src/runbook/mod.rs b/crates/txtx-core/src/runbook/mod.rs index 25f9344e3..c164220ca 100644 --- a/crates/txtx-core/src/runbook/mod.rs +++ b/crates/txtx-core/src/runbook/mod.rs @@ -6,10 +6,9 @@ use kit::types::frontend::ActionItemRequestType; use kit::types::ConstructDid; use serde_json::{json, Value as JsonValue}; use std::collections::{HashMap, HashSet, VecDeque}; -use txtx_addon_kit::hcl::structure::BlockLabel; use txtx_addon_kit::hcl::Span; use txtx_addon_kit::helpers::fs::FileLocation; -use txtx_addon_kit::helpers::hcl::RawHclContent; +use txtx_addon_kit::helpers::hcl::RunbookSource; use txtx_addon_kit::types::commands::{CommandExecutionResult, DependencyExecutionResultCache}; use txtx_addon_kit::types::diagnostics::DiagnosticSpan; use txtx_addon_kit::types::stores::ValueStore; @@ -123,21 +122,24 @@ impl Runbook { PackageId::from_file(&location, &self.runbook_id, &package_name).map_err(|e| e)?; package_ids.push(package_id.clone()); - let mut blocks = raw_content.into_blocks().map_err(|diag| diag.location(&location))?; + let mut constructs = + raw_content.into_constructs().map_err(|diag| diag.location(&location))?; - while let Some(block) = blocks.pop_front() { - match block.ident.value().as_str() { + while let Some(construct) = constructs.pop_front() { + match construct.get_construct_type() { "flow" => { - let Some(BlockLabel::String(name)) = block.labels.first() else { + let Some(construct_instance_name) = construct.get_construct_instance_name() + else { + // TODO: return error? continue; }; - let flow_name = name.to_string(); + let flow_name = construct_instance_name.to_string(); let flow_context = FlowContext::new( &flow_name, &self.runbook_id, ¤t_top_level_value_store, ); - flow_map.push((flow_context, block.body.attributes().cloned().collect())); + flow_map.push((flow_context, construct.get_attributes())); } _ => {} } @@ -239,7 +241,7 @@ impl Runbook { .unwrap(); let diag = diag .location(&construct_id.construct_location) - .set_span_range(command_instance.block.span()); + .set_span_range(command_instance.construct.get_span()); vec![diag .clone() .set_diagnostic_span(get_source_context_for_diagnostic(&diag, &sources))] @@ -793,7 +795,7 @@ impl RunbookTopLevelInputsMap { #[derive(Clone, Debug)] pub struct RunbookSources { /// Map of files required to construct the runbook - pub tree: HashMap, + pub tree: HashMap, } impl RunbookSources { @@ -802,10 +804,10 @@ impl RunbookSources { } pub fn add_source(&mut self, name: String, location: FileLocation, content: String) { - self.tree.insert(location, (name, RawHclContent::from_string(content))); + self.tree.insert(location, (name, RunbookSource::from_hcl_string(content))); } - pub fn to_vec_dequeue(&self) -> VecDeque<(FileLocation, String, RawHclContent)> { + pub fn to_vec_dequeue(&self) -> VecDeque<(FileLocation, String, RunbookSource)> { self.tree .iter() .map(|(file_location, (package_name, raw_content))| { @@ -831,7 +833,7 @@ pub fn get_source_context_for_diagnostic( else { return None; }; - let raw_content_string = raw_content.to_string(); + let raw_content_string = raw_content.as_hcl_str(); let mut lines = 1; let mut cols = 1; let mut span = DiagnosticSpan::new(); diff --git a/crates/txtx-core/src/runbook/runtime_context.rs b/crates/txtx-core/src/runbook/runtime_context.rs index 14bab0131..92bf66642 100644 --- a/crates/txtx-core/src/runbook/runtime_context.rs +++ b/crates/txtx-core/src/runbook/runtime_context.rs @@ -1,3 +1,4 @@ +use kit::helpers::hcl::RunbookConstruct; use kit::indexmap::IndexMap; use kit::types::cloud_interface::CloudServiceContext; use serde::Deserialize; @@ -8,7 +9,7 @@ use txtx_addon_kit::types::commands::DependencyExecutionResultCache; use txtx_addon_kit::types::stores::AddonDefaults; use txtx_addon_kit::types::stores::ValueStore; use txtx_addon_kit::{ - hcl::structure::{Block, BlockLabel}, + hcl::structure::Block, helpers::fs::FileLocation, types::{ commands::{ @@ -194,12 +195,12 @@ impl RuntimeContext { self.addons_context.register(&package_id.did(), "std", false).unwrap(); - let blocks = - raw_content.into_blocks().map_err(|diag| vec![diag.location(&location)])?; + let constructs = + raw_content.into_constructs().map_err(|diag| vec![diag.location(&location)])?; let _ = self - .register_addons_from_blocks( - blocks, + .register_addons_from_constructs( + constructs, &package_id, &location, runbook_workspace_context, @@ -218,9 +219,9 @@ impl RuntimeContext { } } - pub fn register_addons_from_blocks( + pub fn register_addons_from_constructs( &mut self, - mut blocks: VecDeque, + mut constructs: VecDeque, package_id: &PackageId, location: &FileLocation, runbook_workspace_context: &mut RunbookWorkspaceContext, @@ -228,18 +229,19 @@ impl RuntimeContext { ) -> Result<(), Vec> { let mut diagnostics = vec![]; let dependencies_execution_results = DependencyExecutionResultCache::new(); - while let Some(block) = blocks.pop_front() { + while let Some(construct) = constructs.pop_front() { // parse addon blocks to load that addon - match block.ident.value().as_str() { + match construct.get_construct_type() { "addon" => { - let Some(BlockLabel::String(name)) = block.labels.first() else { + let Some(construct_instance_name) = construct.get_construct_instance_name() + else { diagnostics.push( Diagnostic::error_from_string("addon name missing".into()) .location(&location), ); continue; }; - let addon_id = name.to_string(); + let addon_id = construct_instance_name.to_string(); self.register_addon(&addon_id, &package_id.did())?; let existing_addon_defaults = runbook_workspace_context @@ -249,7 +251,7 @@ impl RuntimeContext { let addon_defaults = self .generate_addon_defaults_from_block( existing_addon_defaults, - &block, + &construct, &addon_id, &package_id, &dependencies_execution_results, @@ -275,7 +277,7 @@ impl RuntimeContext { pub fn generate_addon_defaults_from_block( &self, existing_addon_defaults: Option, - block: &Block, + construct: &RunbookConstruct, addon_id: &str, package_id: &PackageId, dependencies_execution_results: &DependencyExecutionResultCache, @@ -284,8 +286,8 @@ impl RuntimeContext { ) -> Result { let mut addon_defaults = existing_addon_defaults.unwrap_or(AddonDefaults::new(addon_id)); - let map_entries = self.evaluate_hcl_map_blocks( - block.body.blocks().collect(), + let map_entries: IndexMap> = self.evaluate_hcl_map_blocks( + construct.get_sub_constructs(), dependencies_execution_results, package_id, runbook_workspace_context, @@ -555,14 +557,14 @@ impl AddonsContext { command_id: &str, command_name: &str, package_id: &PackageId, - block: &Block, + construct: &RunbookConstruct, location: &FileLocation, ) -> Result { let factory = self .get_factory(namespace, &package_id.did()) .map_err(|diag| diag.location(location))?; let command_id = CommandId::Action(command_id.to_string()); - factory.create_command_instance(&command_id, namespace, command_name, block, package_id) + factory.create_command_instance(&command_id, namespace, command_name, construct, package_id) } pub fn create_signer_instance( @@ -570,7 +572,7 @@ impl AddonsContext { namespaced_action: &str, signer_name: &str, package_id: &PackageId, - block: &Block, + construct: &RunbookConstruct, location: &FileLocation, ) -> Result { let Some((namespace, signer_id)) = namespaced_action.split_once("::") else { @@ -579,7 +581,7 @@ impl AddonsContext { let ctx = self .get_factory(namespace, &package_id.did()) .map_err(|diag| diag.location(location))?; - ctx.create_signer_instance(signer_id, namespace, signer_name, block, package_id) + ctx.create_signer_instance(signer_id, namespace, signer_name, construct, package_id) } } @@ -599,7 +601,7 @@ impl AddonConstructFactory { command_id: &CommandId, namespace: &str, command_name: &str, - block: &Block, + construct: &RunbookConstruct, package_id: &PackageId, ) -> Result { let Some(pre_command_spec) = self.commands.get(command_id) else { @@ -618,7 +620,7 @@ impl AddonConstructFactory { let command_instance = CommandInstance { specification: command_spec.clone(), name: command_name.to_string(), - block: block.clone(), + construct: construct.clone(), package_id: package_id.clone(), typing, namespace: namespace.to_string(), @@ -634,7 +636,7 @@ impl AddonConstructFactory { signer_id: &str, namespace: &str, signer_name: &str, - block: &Block, + construct: &RunbookConstruct, package_id: &PackageId, ) -> Result { let Some(signer_spec) = self.signers.get(signer_id) else { @@ -646,7 +648,7 @@ impl AddonConstructFactory { Ok(SignerInstance { name: signer_name.to_string(), specification: signer_spec.clone(), - block: block.clone(), + construct: construct.clone(), package_id: package_id.clone(), namespace: namespace.to_string(), }) diff --git a/crates/txtx-core/src/runbook/workspace_context.rs b/crates/txtx-core/src/runbook/workspace_context.rs index e59a3182b..bedc585ae 100644 --- a/crates/txtx-core/src/runbook/workspace_context.rs +++ b/crates/txtx-core/src/runbook/workspace_context.rs @@ -1,17 +1,15 @@ use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; use crate::runbook::embedded_runbook::EmbeddedRunbookInstanceBuilder; -use crate::runbook::RawHclContent; +use crate::runbook::RunbookSource; use crate::std::commands; use crate::types::PreConstructData; +use kit::helpers::hcl::ConstructExpression; use txtx_addon_kit::hcl::expr::{Expression, TraversalOperator}; -use txtx_addon_kit::hcl::structure::BlockLabel; use txtx_addon_kit::hcl::template::Element; use txtx_addon_kit::hcl::Span; use txtx_addon_kit::helpers::fs::{get_txtx_files_paths, FileLocation}; -use txtx_addon_kit::helpers::hcl::{ - visit_optional_untyped_attribute, visit_required_string_literal_attribute, -}; +use txtx_addon_kit::helpers::hcl::visit_optional_untyped_attribute; use txtx_addon_kit::indexmap::IndexMap; use txtx_addon_kit::types::commands::{CommandId, CommandInstance, CommandInstanceType}; use txtx_addon_kit::types::diagnostics::Diagnostic; @@ -119,14 +117,14 @@ impl RunbookWorkspaceContext { let package_id = PackageId::from_file(&location, &self.runbook_id, &package_name) .map_err(|e| vec![e])?; - let mut blocks = - raw_content.into_blocks().map_err(|diag| vec![diag.location(&location)])?; + let mut constructs = + raw_content.into_constructs().map_err(|diag| vec![diag.location(&location)])?; - while let Some(block) = blocks.pop_front() { - match block.ident.value().as_str() { + while let Some(construct) = constructs.pop_front() { + match construct.get_construct_type() { "import" => { // imports are the only constructs that we need to process in this step - let Some(BlockLabel::String(name)) = block.labels.first() else { + let Some(name) = construct.get_construct_instance_name() else { diagnostics.push( Diagnostic::error_from_string("import name missing".into()) .location(&location), @@ -134,10 +132,21 @@ impl RunbookWorkspaceContext { continue; }; - let path = visit_required_string_literal_attribute("path", &block).unwrap(); // todo(lgalabru) - println!("Loading {} at path ({path})", name.to_string()); + let path = + match construct.get_required_string_literal_from_attribute("path") { + Ok(path) => path, + Err(e) => { + diagnostics.push( + Diagnostic::error_from_string(format!( + "path attribute missing for import '{}'", + name + )) + .location(&location), + ); + continue; + } + }; - // todo(lgalabru): revisit this approach, filesystem access needs to be abstracted. let mut imported_package_location = location.get_parent_location().map_err(|e| { vec![diagnosed_error!("{}", e.to_string()).location(&location)] @@ -145,6 +154,7 @@ impl RunbookWorkspaceContext { imported_package_location.append_path(&path).unwrap(); + // todo(lgalabru): revisit this approach, filesystem access needs to be abstracted. match std::fs::read_dir(imported_package_location.to_string()) { Ok(_) => { let files = get_txtx_files_paths( @@ -159,7 +169,7 @@ impl RunbookWorkspaceContext { let file_location = FileLocation::from_path(file_path); if !files_visited.contains(&file_location) { let raw_content = - RawHclContent::from_file_location(&file_location) + RunbookSource::from_file_location(&file_location) .map_err(|diag| vec![diag])?; let module_name = name.to_string(); sources.push_back(( @@ -172,7 +182,7 @@ impl RunbookWorkspaceContext { } Err(_) => { if !files_visited.contains(&imported_package_location) { - let raw_content = RawHclContent::from_file_location(&location) + let raw_content = RunbookSource::from_file_location(&location) .map_err(|diag| vec![diag])?; let module_name = name.to_string(); sources.push_back(( @@ -187,14 +197,14 @@ impl RunbookWorkspaceContext { let _ = self.index_construct( name.to_string(), location.clone(), - PreConstructData::Import(block.clone()), + PreConstructData::Import(construct.clone()), &package_id, graph_context, execution_context, ); } "variable" => { - let Some(BlockLabel::String(name)) = block.labels.first() else { + let Some(name) = construct.get_construct_instance_name() else { diagnostics.push( Diagnostic::error_from_string("variable name missing".into()) .location(&location), @@ -204,14 +214,14 @@ impl RunbookWorkspaceContext { let _ = self.index_construct( name.to_string(), location.clone(), - PreConstructData::Variable(block.clone()), + PreConstructData::Variable(construct.clone()), &package_id, graph_context, execution_context, ); } "module" => { - let Some(BlockLabel::String(name)) = block.labels.first() else { + let Some(name) = construct.get_construct_instance_name() else { diagnostics.push( Diagnostic::error_from_string("module name missing".into()) .location(&location), @@ -221,14 +231,14 @@ impl RunbookWorkspaceContext { let _ = self.index_construct( name.to_string(), location.clone(), - PreConstructData::Module(block.clone()), + PreConstructData::Module(construct.clone()), &package_id, graph_context, execution_context, ); } "output" => { - let Some(BlockLabel::String(name)) = block.labels.first() else { + let Some(name) = construct.get_construct_instance_name() else { diagnostics.push( Diagnostic::error_from_string("output name missing".into()) .location(&location), @@ -238,16 +248,17 @@ impl RunbookWorkspaceContext { let _ = self.index_construct( name.to_string(), location.clone(), - PreConstructData::Output(block.clone()), + PreConstructData::Output(construct.clone()), &package_id, graph_context, execution_context, ); } "action" => { - let (Some(command_name), Some(namespaced_action)) = - (block.labels.get(0), block.labels.get(1)) - else { + let (Some(command_name), Some(namespaced_action)) = ( + construct.get_construct_instance_name(), + construct.get_command_instance_type(), + ) else { diagnostics.push( Diagnostic::error_from_string("invalid action syntax: expected `action \"action_name\" \"namespace::action\"".into()) .location(&location), @@ -263,9 +274,9 @@ impl RunbookWorkspaceContext { match runtime_context.addons_context.create_action_instance( namespace, command_id, - command_name.as_str(), + command_name, &package_id, - &block, + &construct, &location, ) { Ok(command_instance) => { @@ -284,7 +295,7 @@ impl RunbookWorkspaceContext { diagnostics.push( diagnostic .location(&location) - .set_span_range(block.span()) + .set_span_range(construct.get_span()) .set_diagnostic_span(span), ); continue; @@ -293,7 +304,7 @@ impl RunbookWorkspaceContext { } "signer" => { let (Some(signer_name), Some(namespaced_signer_cmd)) = - (block.labels.get(0), block.labels.get(1)) + (construct.get_construct_instance_name(), construct.get_command_instance_type()) else { diagnostics.push( Diagnostic::error_from_string("signer syntax invalid".into()) @@ -302,10 +313,10 @@ impl RunbookWorkspaceContext { continue; }; match runtime_context.addons_context.create_signer_instance( - &namespaced_signer_cmd.as_str(), - signer_name.as_str(), + &namespaced_signer_cmd, + signer_name, &package_id, - &block, + &construct, &location, ) { Ok(signer_instance) => { @@ -325,7 +336,7 @@ impl RunbookWorkspaceContext { } } "runbook" => { - let Some(runbook_name) = block.labels.get(0) else { + let Some(runbook_name) = construct.get_construct_instance_name() else { diagnostics.push( Diagnostic::error_from_string("'runbook' syntax invalid".into()) .location(&location), @@ -333,9 +344,9 @@ impl RunbookWorkspaceContext { continue; }; let runbook_name = runbook_name.to_string(); - let embedded_runbook_location = - visit_required_string_literal_attribute("location", &block).unwrap(); - println!("Loading {runbook_name} at path ({embedded_runbook_location})"); + let embedded_runbook_location = construct + .get_required_string_literal_from_attribute("location") + .unwrap(); let imported_package_location = location.get_parent_location().map_err(|e| { @@ -364,7 +375,7 @@ impl RunbookWorkspaceContext { loc, &runbook_name.to_string(), &package_id, - &block, + &construct, &mut runtime_context.addons_context, ) .await @@ -388,7 +399,7 @@ impl RunbookWorkspaceContext { } } "addon" => { - let Some(BlockLabel::String(addon_id)) = block.labels.first() else { + let Some(name) = construct.get_construct_instance_name() else { diagnostics.push( Diagnostic::error_from_string("addon name missing".into()) .location(&location), @@ -396,9 +407,9 @@ impl RunbookWorkspaceContext { continue; }; let _ = self.index_construct( - addon_id.to_string(), + name.to_string(), location.clone(), - PreConstructData::Addon(block.clone()), + PreConstructData::Addon(construct.clone()), &package_id, graph_context, execution_context, @@ -485,7 +496,7 @@ impl RunbookWorkspaceContext { let construct_did = construct_id.did(); self.constructs.insert(construct_did.clone(), construct_id.clone()); let construct_instance_type = match construct_data { - PreConstructData::Module(block) => { + PreConstructData::Module(construct) => { // if construct_name.eq("runbook") && self.runbook_metadata_construct_did.is_none() { // self.runbook_metadata_construct_did = Some(construct_did.clone()); // } @@ -494,40 +505,40 @@ impl RunbookWorkspaceContext { ConstructInstanceType::Executable(CommandInstance { specification: commands::new_module_specification(), name: construct_name.clone(), - block: block.clone(), + construct: construct.clone(), package_id: package_id.clone(), namespace: construct_name.clone(), typing: CommandInstanceType::Module, }) } - PreConstructData::Variable(block) => { + PreConstructData::Variable(construct) => { package.variables_dids.insert(construct_did.clone()); package.variables_did_lookup.insert(construct_name.clone(), construct_did.clone()); ConstructInstanceType::Executable(CommandInstance { specification: commands::new_variable_specification(), name: construct_name.clone(), - block: block.clone(), + construct: construct.clone(), package_id: package_id.clone(), namespace: construct_name.clone(), typing: CommandInstanceType::Variable, }) } - PreConstructData::Addon(block) => { + PreConstructData::Addon(construct) => { package.addons_dids.insert(construct_did.clone()); package.addons_did_lookup.insert(construct_name.clone(), construct_did.clone()); ConstructInstanceType::Addon(AddonInstance { - block: block.clone(), + construct: construct.clone(), package_id: package_id.clone(), addon_id: construct_name.clone(), }) } - PreConstructData::Output(block) => { + PreConstructData::Output(construct) => { package.outputs_dids.insert(construct_did.clone()); package.outputs_did_lookup.insert(construct_name.clone(), construct_did.clone()); ConstructInstanceType::Executable(CommandInstance { specification: commands::new_output_specification(), name: construct_name.clone(), - block: block.clone(), + construct: construct.clone(), package_id: package_id.clone(), namespace: construct_name.clone(), typing: CommandInstanceType::Output, @@ -596,7 +607,7 @@ impl RunbookWorkspaceContext { ) -> Vec { let mut embedded_runbook_inputs = vec![]; for input in command_instance.specification.inputs.iter() { - let res = visit_optional_untyped_attribute(&input.name, &command_instance.block); + let res = command_instance.construct.get_expression_from_attribute(&input.name); if let Some(expr) = res { if let Some(input_names) = self.get_top_level_input_name_from_expression_reference(&expr) @@ -629,8 +640,8 @@ impl RunbookWorkspaceContext { addon_instance: &AddonInstance, ) -> Vec { let mut embedded_runbook_inputs = vec![]; - for attribute in addon_instance.block.body.attributes() { - let expr = &attribute.value; + for attribute in addon_instance.construct.get_attributes() { + let expr = &attribute.get_value(); if let Some(input_names) = self.get_top_level_input_name_from_expression_reference(&expr) { @@ -672,7 +683,7 @@ impl RunbookWorkspaceContext { continue; }; let res = - visit_optional_untyped_attribute(&input.name, &embedded_runbook_instance.block); + embedded_runbook_instance.construct.get_expression_from_attribute(&input.name); if let Some(expr) = res { if let Some(input_names) = self.get_top_level_input_name_from_expression_reference(&expr) @@ -692,9 +703,9 @@ impl RunbookWorkspaceContext { fn get_top_level_input_name_from_expression_reference( &self, - expression: &Expression, + expression: &ConstructExpression, ) -> Option> { - if let Some(traversal) = expression.as_traversal() { + if let Some(traversal) = expression.expect_hcl_expression().as_traversal() { let Some(root) = traversal.expr.as_variable() else { return None; }; @@ -709,7 +720,7 @@ impl RunbookWorkspaceContext { return Some(vec![top_level_input_name]); }; } - } else if let Some(arr) = expression.as_array() { + } else if let Some(arr) = expression.expect_hcl_expression().as_array() { let mut res = vec![]; for expr in arr.iter() { if let Some(mut input_name) = @@ -719,7 +730,7 @@ impl RunbookWorkspaceContext { } } return Some(res); - } else if let Some(obj) = expression.as_object() { + } else if let Some(obj) = expression.expect_hcl_expression().as_object() { let mut res = vec![]; for (_, object_value) in obj.iter() { if let Some(mut input_name) = @@ -729,7 +740,7 @@ impl RunbookWorkspaceContext { } } return Some(res); - } else if let Some(string_template) = expression.as_string_template() { + } else if let Some(string_template) = expression.expect_hcl_expression().as_string_template() { let mut res = vec![]; for element in string_template.into_iter() { match element { @@ -756,7 +767,7 @@ impl RunbookWorkspaceContext { pub fn try_resolve_construct_reference_in_expression( &self, source_package_id: &PackageId, - expression: &Expression, + expression: &ConstructExpression, ) -> Result, VecDeque)>, String> { let Some(traversal) = expression.as_traversal() else { return Ok(None); diff --git a/crates/txtx-core/src/types/construct/mod.rs b/crates/txtx-core/src/types/construct/mod.rs index 46a4b9249..e255fd023 100644 --- a/crates/txtx-core/src/types/construct/mod.rs +++ b/crates/txtx-core/src/types/construct/mod.rs @@ -1,3 +1,4 @@ +use kit::helpers::hcl::RunbookConstruct; use txtx_addon_kit::types::embedded_runbooks::EmbeddedRunbookInstance; use txtx_addon_kit::{ hcl::structure::Block, @@ -6,13 +7,13 @@ use txtx_addon_kit::{ #[derive(Debug)] pub enum PreConstructData { - Variable(Block), - Module(Block), - Output(Block), - Import(Block), + Variable(RunbookConstruct), + Module(RunbookConstruct), + Output(RunbookConstruct), + Import(RunbookConstruct), Action(CommandInstance), Signer(SignerInstance), - Addon(Block), + Addon(RunbookConstruct), EmbeddedRunbook(EmbeddedRunbookInstance), Root, } @@ -32,35 +33,35 @@ impl PreConstructData { } } - pub fn as_import(&self) -> Option<&Block> { + pub fn as_import(&self) -> Option<&RunbookConstruct> { match self { PreConstructData::Import(data) => Some(&data), _ => None, } } - pub fn as_input(&self) -> Option<&Block> { + pub fn as_input(&self) -> Option<&RunbookConstruct> { match self { PreConstructData::Variable(data) => Some(&data), _ => None, } } - pub fn as_output(&self) -> Option<&Block> { + pub fn as_output(&self) -> Option<&RunbookConstruct> { match self { PreConstructData::Output(data) => Some(&data), _ => None, } } - pub fn as_module(&self) -> Option<&Block> { + pub fn as_module(&self) -> Option<&RunbookConstruct> { match self { PreConstructData::Module(data) => Some(&data), _ => None, } } - pub fn as_addon(&self) -> Option<&Block> { + pub fn as_addon(&self) -> Option<&RunbookConstruct> { match self { PreConstructData::Addon(data) => Some(&data), _ => None,