diff --git a/pkg/tf2pulumi/convert/convert.go b/pkg/tf2pulumi/convert/convert.go index 4e4bd5f81..46c26a368 100644 --- a/pkg/tf2pulumi/convert/convert.go +++ b/pkg/tf2pulumi/convert/convert.go @@ -123,7 +123,7 @@ func Convert(opts Options) (map[string][]byte, Diagnostics, error) { var genDiags hcl.Diagnostics switch opts.TargetLanguage { case LanguageTypescript: - generatedFiles, genDiags, err = hcl2nodejs.GenerateProgram(program) + generatedFiles, genDiags, err = hcl2nodejs.GenerateCode(program, opts.ConvertToComponentResource) diagnostics = append(diagnostics, genDiags...) case LanguagePulumi: generatedFiles = map[string][]byte{} @@ -170,6 +170,8 @@ type Options struct { // AnnotateNodesWithLocations is true if the generated source code should contain comments that annotate top-level // nodes with their original source locations. AnnotateNodesWithLocations bool + // Whether to convert the given terraform module to a runnable program, or a Pulumi ComponentResource file. + ConvertToComponentResource bool // FilterResourceNames, if true, removes the property indicated by ResourceNameProperty from all resources in the // graph. FilterResourceNames bool diff --git a/pkg/tf2pulumi/convert/tf12.go b/pkg/tf2pulumi/convert/tf12.go index 83c0b31a4..d39345803 100644 --- a/pkg/tf2pulumi/convert/tf12.go +++ b/pkg/tf2pulumi/convert/tf12.go @@ -330,6 +330,7 @@ type resource struct { rangeVariable *model.Variable isCounted bool isConditional bool + isModule bool block *model.Block } @@ -404,8 +405,28 @@ func (b *tf12binder) declareFile(input *syntax.File) (*file, hcl.Diagnostics) { name: item.Labels[0], } file.nodes = append(file.nodes, o) - // case "module": - // // TODO(pdg): module instances + case "module": + // We are processing a call to a Terraform "Child Module" (https://www.terraform.io/language/modules#child-modules) + + // Treating it similarly to how we would a regular resource. + var terraformType model.Type = model.NewObjectType(make(map[string]model.Type)) + var variableType model.Type = model.NewObjectType(make(map[string]model.Type)) + _, hasCount := item.Body.Attributes["count"] + _, hasForEach := item.Body.Attributes["for_each"] + if hasCount || hasForEach { + variableType = model.NewListType(terraformType) + } + + r := &resource{ + isModule: true, + syntax: item, + name: item.Labels[0], + token: "Terraform Child Module", + terraformType: terraformType, + variableType: variableType, + } + + file.nodes = append(file.nodes, r) case "resource", "data": isDataSource := item.Type == "data" @@ -1583,7 +1604,10 @@ func (b *tf12binder) genResource(w io.Writer, r *resource) hcl.Diagnostics { item := model.BodyItem(r.block) if !r.isDataSource { - r.block.Labels = []string{r.pulumiName, r.token} + r.block.Labels = []string{r.pulumiName} + if !r.isModule { + r.block.Labels = append(r.block.Labels, r.token) + } if r.isConditional { options := r.block.Body.Blocks("options")[0]