diff --git a/README.md b/README.md index e206a4b1..76799c34 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ Usage: tfplugindocs generate [] --providers-schema path to the providers schema JSON file, which contains the output of the terraform providers schema -json command. Setting this flag will skip building the provider and calling Terraform CLI --rendered-provider-name provider name, as generated in documentation (ex. page titles, ...); defaults to the --provider-name --rendered-website-dir output directory based on provider-dir (default: "docs") + --syntax default syntax highlighting format for code blocks (e.g., terraform, hcl) (default: "terraform") --tf-version terraform binary version to download. If not provided, will look for a terraform binary in the local environment. If not found in the environment, will download the latest version of Terraform --website-source-dir templates directory based on provider-dir (default: "templates") --website-temp-dir temporary directory (used during generation) @@ -89,6 +90,7 @@ Usage: tfplugindocs validate [] --provider-dir relative or absolute path to the root provider code directory; this will default to the current working directory if not set --provider-name provider name, as used in Terraform configurations; defaults to the --provider-dir short name (after removing `terraform-provider-` prefix) --providers-schema path to the providers schema JSON file, which contains the output of the terraform providers schema -json command. Setting this flag will skip building the provider and calling Terraform CLI + --syntax default syntax highlighting format for code blocks (e.g., terraform, hcl) (default: "terraform") --tf-version terraform binary version to download. If not provided, will look for a terraform binary in the local environment. If not found in the environment, will download the latest version of Terraform ``` @@ -101,8 +103,9 @@ Usage: tfplugindocs migrate [] --examples-dir examples directory based on provider-dir (default: "examples") --provider-dir relative or absolute path to the root provider code directory when running the command outside the root provider code directory - --templates-dir new website templates directory based on provider-dir; files will be migrated to this directory (default: "templates") --provider-name provider name, as used in Terraform configurations; defaults to the --provider-dir short name (after removing `terraform-provider-` prefix) + --syntax default syntax highlighting format for code blocks (e.g., terraform, hcl) (default: "terraform") + --templates-dir new website templates directory based on provider-dir; files will be migrated to this directory (default: "templates") ``` ### How it Works @@ -383,18 +386,77 @@ using the following data fields and functions: #### Template Functions -| Function | Description | -|-----------------|---------------------------------------------------------------------------------------------------| -| `codefile` | Create a Markdown code block with the content of a file. Path is relative to the repository root. | -| `lower` | Equivalent to [`strings.ToLower`](https://pkg.go.dev/strings#ToLower). | -| `plainmarkdown` | Render Markdown content as plaintext. | -| `prefixlines` | Add a prefix to all (newline-separated) lines in a string. | -| `printf` | Equivalent to [`fmt.Printf`](https://pkg.go.dev/fmt#Printf). | -| `split` | Split string into sub-strings, by a given separator (ex. `split .Name "_"`). | -| `title` | Equivalent to [`cases.Title`](https://pkg.go.dev/golang.org/x/text/cases#Title). | -| `tffile` | A special case of the `codefile` function, designed for Terraform files (i.e. `.tf`). | -| `trimspace` | Equivalent to [`strings.TrimSpace`](https://pkg.go.dev/strings#TrimSpace). | -| `upper` | Equivalent to [`strings.ToUpper`](https://pkg.go.dev/strings#ToUpper). | +| Function | Description | +|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------| +| `codefile` | Create a Markdown code block with the content of a file. Path is relative to the repository root. | +| `lower` | Equivalent to [`strings.ToLower`](https://pkg.go.dev/strings#ToLower). | +| `plainmarkdown` | Render Markdown content as plaintext. | +| `prefixlines` | Add a prefix to all (newline-separated) lines in a string. | +| `printf` | Equivalent to [`fmt.Printf`](https://pkg.go.dev/fmt#Printf). | +| `split` | Split string into sub-strings, by a given separator (ex. `split .Name "_"`). | +| `title` | Equivalent to [`cases.Title`](https://pkg.go.dev/golang.org/x/text/cases#Title). | +| `tffile` | A special case of the `codefile` function, designed for Terraform files (i.e. `.tf`). Supports optional syntax highlighting format parameter. | +| `trimspace` | Equivalent to [`strings.TrimSpace`](https://pkg.go.dev/strings#TrimSpace). | +| `upper` | Equivalent to [`strings.ToUpper`](https://pkg.go.dev/strings#ToUpper). | + +##### Code Block Syntax Formatting + +The `tffile` function and `codefile` function support syntax highlighting for code blocks. The syntax format can be controlled in several ways: + +1. **Command-line flag (default syntax)**: Use the `--syntax` flag when running `generate`, `validate`, or `migrate` commands to set the default syntax highlighting format for all code blocks: + + ```shell + tfplugindocs generate --syntax hcl + ``` + + The default value is `"terraform"` if not specified. + +2. **Template literal override**: Override the default syntax for a specific code block by passing a literal string as the second parameter to `tffile`: + + ```go + {{ tffile . }} + {{ tffile . "hcl" }} + {{ tffile . "terraform" }} + {{ tffile . "mySyntax" }} + ``` + +3. **Template variable override**: Use a template variable to dynamically set the syntax format: + + ```go + {{ $format := .Format }} + {{ tffile . $format }} + ``` + + Or more concisely: + + ```go + {{ tffile . .Format }} + ``` + +**Examples:** + +Using the default syntax (from `--syntax` flag): +```markdown +{{ tffile .ExampleFile }} +``` + +Overriding with a specific syntax: +```markdown +{{ tffile .ExampleFile "hcl" }} +``` + +Using multiple syntaxes in the same template: +```markdown +Default: {{ tffile .ExampleFile }} +HCL: {{ tffile .ExampleFile "hcl" }} +Custom: {{ tffile .ExampleFile "custom" }} +``` + +Using a template variable: +```markdown +{{ $format := "hcl" }} +{{ tffile .ExampleFile $format }} +``` ## Disclaimer diff --git a/internal/cmd/generate.go b/internal/cmd/generate.go index 77dbc96f..d9e5b8ec 100644 --- a/internal/cmd/generate.go +++ b/internal/cmd/generate.go @@ -26,6 +26,7 @@ type generateCmd struct { flagWebsiteTmpDir string flagWebsiteSourceDir string tfVersion string + flagSyntax string } func (cmd *generateCmd) Synopsis() string { @@ -82,6 +83,7 @@ func (cmd *generateCmd) Flags() *flag.FlagSet { fs.StringVar(&cmd.flagWebsiteSourceDir, "website-source-dir", "templates", "templates directory based on provider-dir") fs.StringVar(&cmd.tfVersion, "tf-version", "", "terraform binary version to download. If not provided, will look for a terraform binary in the local environment. If not found in the environment, will download the latest version of Terraform") fs.BoolVar(&cmd.flagIgnoreDeprecated, "ignore-deprecated", false, "don't generate documentation for deprecated resources and data-sources") + fs.StringVar(&cmd.flagSyntax, "syntax", "terraform", "default syntax highlighting format for code blocks (e.g., terraform, hcl)") return fs } @@ -109,6 +111,7 @@ func (cmd *generateCmd) runInternal() error { cmd.flagWebsiteSourceDir, cmd.tfVersion, cmd.flagIgnoreDeprecated, + cmd.flagSyntax, ) if err != nil { return fmt.Errorf("unable to generate website: %w", err) diff --git a/internal/cmd/migrate.go b/internal/cmd/migrate.go index 14e39ec1..9c7ac144 100644 --- a/internal/cmd/migrate.go +++ b/internal/cmd/migrate.go @@ -18,6 +18,7 @@ type migrateCmd struct { flagTemplatesDir string flagExamplesDir string flagProviderName string + flagSyntax string } func (cmd *migrateCmd) Synopsis() string { @@ -69,6 +70,7 @@ func (cmd *migrateCmd) Flags() *flag.FlagSet { fs.StringVar(&cmd.flagTemplatesDir, "templates-dir", "templates", "new website templates directory based on provider-dir; files will be migrated to this directory") fs.StringVar(&cmd.flagExamplesDir, "examples-dir", "examples", "examples directory based on provider-dir; extracted code examples will be migrated to this directory") fs.StringVar(&cmd.flagProviderName, "provider-name", "", "provider name, as used in Terraform configurations; defaults to the --provider-dir short name (after removing `terraform-provider-` prefix)") + fs.StringVar(&cmd.flagSyntax, "syntax", "terraform", "default syntax highlighting format for code blocks (e.g., terraform, hcl)") return fs } @@ -91,6 +93,7 @@ func (cmd *migrateCmd) runInternal() error { cmd.flagTemplatesDir, cmd.flagExamplesDir, cmd.flagProviderName, + cmd.flagSyntax, ) if err != nil { return fmt.Errorf("unable to migrate website: %w", err) diff --git a/internal/cmd/validate.go b/internal/cmd/validate.go index fdd4601e..3de66ecc 100644 --- a/internal/cmd/validate.go +++ b/internal/cmd/validate.go @@ -23,6 +23,7 @@ type validateCmd struct { flagProviderDir string flagProvidersSchema string tfVersion string + flagSyntax string } func (cmd *validateCmd) Synopsis() string { @@ -77,6 +78,7 @@ func (cmd *validateCmd) Flags() *flag.FlagSet { fs.StringVar(&cmd.flagProviderDir, "provider-dir", "", "relative or absolute path to the root provider code directory; this will default to the current working directory if not set") fs.StringVar(&cmd.flagProvidersSchema, "providers-schema", "", "path to the providers schema JSON file, which contains the output of the terraform providers schema -json command. Setting this flag will skip building the provider and calling Terraform CLI") fs.StringVar(&cmd.tfVersion, "tf-version", "", "terraform binary version to download. If not provided, will look for a terraform binary in the local environment. If not found in the environment, will download the latest version of Terraform") + fs.StringVar(&cmd.flagSyntax, "syntax", "terraform", "default syntax highlighting format for code blocks (e.g., terraform, hcl)") return fs } diff --git a/internal/provider/action_template.go b/internal/provider/action_template.go index a0ca1eb7..a53290c4 100644 --- a/internal/provider/action_template.go +++ b/internal/provider/action_template.go @@ -32,7 +32,7 @@ type ActionTemplateType struct { RenderedProviderName string } -func (t actionTemplate) Render(providerDir, name, providerName, renderedProviderName, typeName, exampleFile string, exampleFiles []string, schema *tfjson.ActionSchema) (string, error) { +func (t actionTemplate) Render(providerDir, name, providerName, renderedProviderName, typeName, exampleFile string, exampleFiles []string, schema *tfjson.ActionSchema, syntax string) (string, error) { schemaBuffer := bytes.NewBuffer(nil) err := schemamd.RenderAction(schema, schemaBuffer) if err != nil { @@ -60,7 +60,7 @@ func (t actionTemplate) Render(providerDir, name, providerName, renderedProvider SchemaMarkdown: actionSchemaComment + "\n" + schemaBuffer.String(), RenderedProviderName: renderedProviderName, - }) + }, syntax) } const defaultActionTemplate actionTemplate = `--- diff --git a/internal/provider/action_template_test.go b/internal/provider/action_template_test.go index 7eb3c7e9..0e86aaba 100644 --- a/internal/provider/action_template_test.go +++ b/internal/provider/action_template_test.go @@ -49,7 +49,7 @@ action "scaffolding_example" "example1" { }, } - result, err := tpl.Render("testdata/test-action-dir", "testTemplate", "test-action", "test-action", "action", "action.tf", []string{"action.tf"}, &schema) + result, err := tpl.Render("testdata/test-action-dir", "testTemplate", "test-action", "test-action", "action", "action.tf", []string{"action.tf"}, &schema, "terraform") if err != nil { t.Error(err) } diff --git a/internal/provider/generate.go b/internal/provider/generate.go index b7b72d8d..02fa37e5 100644 --- a/internal/provider/generate.go +++ b/internal/provider/generate.go @@ -109,6 +109,7 @@ var ( type generator struct { ignoreDeprecated bool tfVersion string + syntax string // providerDir is the absolute path to the root provider directory providerDir string @@ -132,7 +133,7 @@ func (g *generator) warnf(format string, a ...interface{}) { g.ui.Warn(fmt.Sprintf(format, a...)) } -func Generate(ui cli.Ui, providerDir, providerName, providersSchemaPath, renderedProviderName, renderedWebsiteDir, examplesDir, websiteTmpDir, templatesDir, tfVersion string, ignoreDeprecated bool) error { +func Generate(ui cli.Ui, providerDir, providerName, providersSchemaPath, renderedProviderName, renderedWebsiteDir, examplesDir, websiteTmpDir, templatesDir, tfVersion string, ignoreDeprecated bool, syntax string) error { // Ensure provider directory is resolved absolute path if providerDir == "" { wd, err := os.Getwd() @@ -163,9 +164,14 @@ func Generate(ui cli.Ui, providerDir, providerName, providersSchemaPath, rendere return fmt.Errorf("expected %q to be a directory", providerDir) } + if syntax == "" { + syntax = "terraform" + } + g := &generator{ ignoreDeprecated: ignoreDeprecated, tfVersion: tfVersion, + syntax: syntax, providerDir: providerDir, providerName: providerName, @@ -772,7 +778,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e slices.Sort(exampleFiles) tmpl := resourceTemplate(tmplData) - render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Data Source", exampleFilePath, exampleFiles, "", "", "", resSchema, nil) + render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Data Source", exampleFilePath, exampleFiles, "", "", "", resSchema, nil, g.syntax) if err != nil { return fmt.Errorf("unable to render data source template %q: %w", rel, err) } @@ -803,7 +809,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e importIdentityConfigFilePath := filepath.Join(g.ProviderExamplesDir(), "resources", resName, "import-by-identity.tf") tmpl := resourceTemplate(tmplData) - render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Resource", exampleFilePath, exampleFiles, importIDConfigFilePath, importIdentityConfigFilePath, importFilePath, resSchema, resIdentitySchema) + render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Resource", exampleFilePath, exampleFiles, importIDConfigFilePath, importIdentityConfigFilePath, importFilePath, resSchema, resIdentitySchema, g.syntax) if err != nil { return fmt.Errorf("unable to render resource template %q: %w", rel, err) } @@ -828,7 +834,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e slices.Sort(exampleFiles) tmpl := functionTemplate(tmplData) - render, err := tmpl.Render(g.providerDir, funcName, g.providerName, g.renderedProviderName, "function", exampleFilePath, exampleFiles, signature) + render, err := tmpl.Render(g.providerDir, funcName, g.providerName, g.renderedProviderName, "function", exampleFilePath, exampleFiles, signature, g.syntax) if err != nil { return fmt.Errorf("unable to render function template %q: %w", rel, err) } @@ -855,7 +861,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e slices.Sort(exampleFiles) tmpl := resourceTemplate(tmplData) - render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Ephemeral Resource", exampleFilePath, exampleFiles, "", "", "", resSchema, nil) + render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Ephemeral Resource", exampleFilePath, exampleFiles, "", "", "", resSchema, nil, g.syntax) if err != nil { return fmt.Errorf("unable to render ephemeral resource template %q: %w", rel, err) } @@ -881,7 +887,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e slices.Sort(exampleFiles) tmpl := actionTemplate(tmplData) - render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Action", exampleFilePath, exampleFiles, actionSchema) + render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Action", exampleFilePath, exampleFiles, actionSchema, g.syntax) if err != nil { return fmt.Errorf("unable to render action template %q: %w", rel, err) } @@ -906,7 +912,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e if resSchema != nil { tmpl := resourceTemplate(tmplData) - render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "List Resource", exampleFilePath, exampleFiles, "", "", "", resSchema, nil) + render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "List Resource", exampleFilePath, exampleFiles, "", "", "", resSchema, nil, g.syntax) if err != nil { return fmt.Errorf("unable to render list resource template %q: %w", rel, err) } @@ -930,7 +936,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e slices.Sort(exampleFiles) tmpl := providerTemplate(tmplData) - render, err := tmpl.Render(g.providerDir, g.providerName, g.renderedProviderName, exampleFilePath, exampleFiles, providerSchema.ConfigSchema) + render, err := tmpl.Render(g.providerDir, g.providerName, g.renderedProviderName, exampleFilePath, exampleFiles, providerSchema.ConfigSchema, g.syntax) if err != nil { return fmt.Errorf("unable to render provider template %q: %w", rel, err) } @@ -943,7 +949,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e } tmpl := docTemplate(tmplData) - err = tmpl.Render(g.providerDir, out) + err = tmpl.Render(g.providerDir, out, g.syntax) if err != nil { return fmt.Errorf("unable to render template %q: %w", rel, err) } diff --git a/internal/provider/migrate.go b/internal/provider/migrate.go index 51c9c70d..416d4ad4 100644 --- a/internal/provider/migrate.go +++ b/internal/provider/migrate.go @@ -28,6 +28,7 @@ type migrator struct { examplesDir string providerName string + syntax string ui cli.Ui } @@ -40,7 +41,7 @@ func (m *migrator) warnf(format string, a ...interface{}) { m.ui.Warn(fmt.Sprintf(format, a...)) } -func Migrate(ui cli.Ui, providerDir string, templatesDir string, examplesDir string, providerName string) error { +func Migrate(ui cli.Ui, providerDir string, templatesDir string, examplesDir string, providerName string, syntax string) error { // Ensure provider directory is resolved absolute path if providerDir == "" { wd, err := os.Getwd() @@ -82,12 +83,17 @@ func Migrate(ui cli.Ui, providerDir string, templatesDir string, examplesDir str return err } + if syntax == "" { + syntax = "terraform" + } + m := &migrator{ providerDir: providerDir, templatesDir: templatesDir, examplesDir: examplesDir, websiteDir: websiteDir, providerName: providerName, + syntax: syntax, ui: ui, } diff --git a/internal/provider/template.go b/internal/provider/template.go index 2d1bfc8a..cab5ee85 100644 --- a/internal/provider/template.go +++ b/internal/provider/template.go @@ -106,17 +106,21 @@ type FunctionTemplateType struct { RenderedProviderName string } -func newTemplate(providerDir, name, text string) (*template.Template, error) { +func newTemplate(providerDir, name, text, syntax string) (*template.Template, error) { tmpl := template.New(name) titleCaser := cases.Title(language.Und) + if syntax == "" { + syntax = "terraform" + } + tmpl.Funcs(map[string]interface{}{ "codefile": codeFile(providerDir), "lower": strings.ToLower, "plainmarkdown": mdplain.PlainMarkdown, "prefixlines": tmplfuncs.PrefixLines, "split": strings.Split, - "tffile": terraformCodeFile(providerDir), + "tffile": terraformCodeFile(providerDir, syntax), "title": titleCaser.String, "trimspace": strings.TrimSpace, "upper": strings.ToUpper, @@ -141,19 +145,24 @@ func codeFile(providerDir string) func(string, string) (string, error) { } } -func terraformCodeFile(providerDir string) func(string) (string, error) { +func terraformCodeFile(providerDir, defaultSyntax string) func(string, ...string) (string, error) { // TODO: omit comment handling - return func(file string) (string, error) { + return func(file string, format ...string) (string, error) { + syntaxFormat := defaultSyntax + if len(format) > 0 && format[0] != "" { + syntaxFormat = format[0] + } + if filepath.IsAbs(file) { - return tmplfuncs.CodeFile("terraform", file) + return tmplfuncs.CodeFile(syntaxFormat, file) } - return tmplfuncs.CodeFile("terraform", filepath.Join(providerDir, file)) + return tmplfuncs.CodeFile(syntaxFormat, filepath.Join(providerDir, file)) } } -func renderTemplate(providerDir, name string, text string, out io.Writer, data interface{}) error { - tmpl, err := newTemplate(providerDir, name, text) +func renderTemplate(providerDir, name string, text string, out io.Writer, data interface{}, syntax string) error { + tmpl, err := newTemplate(providerDir, name, text, syntax) if err != nil { return err } @@ -166,10 +175,10 @@ func renderTemplate(providerDir, name string, text string, out io.Writer, data i return nil } -func renderStringTemplate(providerDir, name, text string, data interface{}) (string, error) { +func renderStringTemplate(providerDir, name, text string, data interface{}, syntax string) (string, error) { var buf bytes.Buffer - err := renderTemplate(providerDir, name, text, &buf, data) + err := renderTemplate(providerDir, name, text, &buf, data, syntax) if err != nil { return "", err } @@ -177,16 +186,16 @@ func renderStringTemplate(providerDir, name, text string, data interface{}) (str return buf.String(), nil } -func (t docTemplate) Render(providerDir string, out io.Writer) error { +func (t docTemplate) Render(providerDir string, out io.Writer, syntax string) error { s := string(t) if s == "" { return nil } - return renderTemplate(providerDir, "docTemplate", s, out, nil) + return renderTemplate(providerDir, "docTemplate", s, out, nil, syntax) } -func (t providerTemplate) Render(providerDir, providerName, renderedProviderName, exampleFile string, exampleFiles []string, schema *tfjson.Schema) (string, error) { +func (t providerTemplate) Render(providerDir, providerName, renderedProviderName, exampleFile string, exampleFiles []string, schema *tfjson.Schema, syntax string) (string, error) { schemaBuffer := bytes.NewBuffer(nil) err := schemamd.Render(schema, schemaBuffer) if err != nil { @@ -212,10 +221,10 @@ func (t providerTemplate) Render(providerDir, providerName, renderedProviderName SchemaMarkdown: schemaComment + "\n" + schemaBuffer.String(), RenderedProviderName: renderedProviderName, - }) + }, syntax) } -func (t resourceTemplate) Render(providerDir, name, providerName, renderedProviderName, typeName, exampleFile string, exampleFiles []string, importIDConfigFile, importIdentityConfigFile, importCmdFile string, schema *tfjson.Schema, identitySchema *tfjson.IdentitySchema) (string, error) { +func (t resourceTemplate) Render(providerDir, name, providerName, renderedProviderName, typeName, exampleFile string, exampleFiles []string, importIDConfigFile, importIdentityConfigFile, importCmdFile string, schema *tfjson.Schema, identitySchema *tfjson.IdentitySchema, syntax string) (string, error) { schemaBuffer := bytes.NewBuffer(nil) err := schemamd.Render(schema, schemaBuffer) if err != nil { @@ -272,10 +281,10 @@ func (t resourceTemplate) Render(providerDir, name, providerName, renderedProvid SchemaMarkdown: schemaComment + "\n" + schemaBuffer.String(), RenderedProviderName: renderedProviderName, - }) + }, syntax) } -func (t functionTemplate) Render(providerDir, name, providerName, renderedProviderName, typeName, exampleFile string, exampleFiles []string, signature *tfjson.FunctionSignature) (string, error) { +func (t functionTemplate) Render(providerDir, name, providerName, renderedProviderName, typeName, exampleFile string, exampleFiles []string, signature *tfjson.FunctionSignature, syntax string) (string, error) { funcSig, err := functionmd.RenderSignature(name, signature) if err != nil { return "", fmt.Errorf("unable to render function signature: %w", err) @@ -317,7 +326,7 @@ func (t functionTemplate) Render(providerDir, name, providerName, renderedProvid FunctionVariadicArgumentMarkdown: variadicComment + "\n" + funcVarArg, RenderedProviderName: renderedProviderName, - }) + }, syntax) } const defaultResourceTemplate resourceTemplate = `--- diff --git a/internal/provider/template_test.go b/internal/provider/template_test.go index 426e4ff2..2e8c6302 100644 --- a/internal/provider/template_test.go +++ b/internal/provider/template_test.go @@ -53,7 +53,7 @@ provider "scaffolding" { MultiLineTest: `This text used multiple lines`, Code: "provider.tf", - }) + }, "terraform") if err != nil { t.Error(err) @@ -93,7 +93,7 @@ provider "scaffolding" { }, } - result, err := tpl.Render("testdata/test-provider-dir", "testTemplate", "test-provider", "test-provider", "Resource", "provider.tf", []string{"provider.tf"}, "", "", "", &schema, nil) + result, err := tpl.Render("testdata/test-provider-dir", "testTemplate", "test-provider", "test-provider", "Resource", "provider.tf", []string{"provider.tf"}, "", "", "", &schema, nil, "terraform") if err != nil { t.Error(err) } @@ -133,7 +133,7 @@ provider "scaffolding" { }, } - result, err := tpl.Render("testdata/test-provider-dir", "testTemplate", "test-provider", "provider.tf", []string{"provider.tf"}, &schema) + result, err := tpl.Render("testdata/test-provider-dir", "testTemplate", "test-provider", "provider.tf", []string{"provider.tf"}, &schema, "terraform") if err != nil { t.Error(err) } @@ -143,3 +143,97 @@ provider "scaffolding" { t.Errorf("expected: %+v, got: %+v", expectedString, cleanedResult) } } + +func TestTffileSyntax(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + template string + syntax string + expectedSyntax string + }{ + { + name: "default syntax with terraform", + template: `{{ tffile .Code }}`, + syntax: "terraform", + expectedSyntax: "terraform", + }, + { + name: "default syntax with hcl", + template: `{{ tffile .Code }}`, + syntax: "hcl", + expectedSyntax: "hcl", + }, + { + name: "override with hcl", + template: `{{ tffile .Code "hcl" }}`, + syntax: "terraform", + expectedSyntax: "hcl", + }, + { + name: "override with terraform", + template: `{{ tffile .Code "terraform" }}`, + syntax: "hcl", + expectedSyntax: "terraform", + }, + { + name: "override with custom syntax", + template: `{{ tffile .Code "mySyntax" }}`, + syntax: "terraform", + expectedSyntax: "mySyntax", + }, + { + name: "multiple tffile calls with different syntaxes", + template: `Default: {{ tffile .Code }} +Override: {{ tffile .Code "hcl" }} +Custom: {{ tffile .Code "custom" }}`, + syntax: "terraform", + expectedSyntax: "terraform", // We'll check for all three in the result + }, + { + name: "override with variable format", + template: `{{ $format := .Format }}{{ tffile .Code $format }}`, + syntax: "terraform", + expectedSyntax: "hcl", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + data := struct { + Code string + Format string + }{ + Code: "provider.tf", + Format: "hcl", // Used for the variable format test case + } + + result, err := renderStringTemplate("testdata/test-provider-dir", "testTemplate", tt.template, data, tt.syntax) + + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + // Check that the expected syntax appears in the code block + if !strings.Contains(result, "```"+tt.expectedSyntax) { + t.Errorf("expected syntax %q in result, got: %s", tt.expectedSyntax, result) + } + + // For the multiple calls test, verify all three syntaxes appear + if tt.name == "multiple tffile calls with different syntaxes" { + if !strings.Contains(result, "```terraform") { + t.Errorf("expected terraform syntax in result, got: %s", result) + } + if !strings.Contains(result, "```hcl") { + t.Errorf("expected hcl syntax in result, got: %s", result) + } + if !strings.Contains(result, "```custom") { + t.Errorf("expected custom syntax in result, got: %s", result) + } + } + }) + } +}