Support FixedIndent, add tests

This commit is contained in:
Andinus 2024-11-16 11:11:07 +05:30
parent 5b7e923bd8
commit c9c7dd1b22
Signed by: andinus
GPG Key ID: B67D55D482A799FD
2 changed files with 127 additions and 12 deletions

@ -16,11 +16,12 @@ type Hash map[string]interface{}
type Option struct {
Delimiters [2]string
NameLabel string // Identify the template to be used
TemplateDir string // directory where templates are located
TemplateExtension string // appended on the label to idenfity the template
DieOnBadParams bool // attempt to populate a variable that doesn't exist should result in an error
TemplateDir string // Directory where templates are located
TemplateExtension string // Appended on the label to idenfity the template
DieOnBadParams bool // Attempt to populate a variable that doesn't exist should result in an error
ShowLabels bool // Prepend & Append a string to every template, helpful in debugging
CommentDelimiters [2]string // Used in conjunction with ShowLabels, if HTML then use '<!--', '-->'
FixedIndent bool // Intended to improve readability when inspecting nested templates
}
type TemplateNest struct {
@ -118,6 +119,7 @@ func (nest *TemplateNest) index(filePath string) (TemplateFileIndex, error) {
if err != nil {
return TemplateFileIndex{}, fmt.Errorf("error reading file (`%s`): %w", filePath, err)
}
// Capture last modified time
fileInfo, err := os.Stat(filePath)
if err != nil {
@ -134,6 +136,7 @@ func (nest *TemplateNest) index(filePath string) (TemplateFileIndex, error) {
"%s\\s*(.+?)\\s*%s", regexp.QuoteMeta(delimiterStart), regexp.QuoteMeta(delimiterEnd),
))
contentsStr := string(contents)
matches := re.FindAllStringSubmatchIndex(string(contents), -1)
for _, match := range matches {
if len(match) < 4 {
@ -148,15 +151,33 @@ func (nest *TemplateNest) index(filePath string) (TemplateFileIndex, error) {
varName := string(contents[nameStartIdx:nameEndIdx])
variableNames[varName] = struct{}{}
// If fixed indent is enabled then record the indent level for this
// variable. To get the indent level we look at each character in
// reverse from the start position of the variable until we find a
// newline character.
indentLevel := 0
if nest.option.FixedIndent {
// If we do not encounter a newline then that means this variable is
// on the first line, we take the start position as the indent
// level.
lineStartIdx := strings.LastIndex(contentsStr[:startIdx], "\n")
if lineStartIdx == -1 {
indentLevel = startIdx
} else {
indentLevel = startIdx - lineStartIdx - 1
}
}
variables = append(variables, TemplateFileVariable{
Name: varName,
StartPosition: uint(startIdx),
EndPosition: uint(endIdx),
IndentLevel: uint(indentLevel),
})
}
fileIndex := TemplateFileIndex{
Contents: string(contents),
Contents: contentsStr,
LastModified: fileInfo.ModTime(),
VariableNames: variableNames,
Variables: variables,
@ -261,15 +282,17 @@ func (nest *TemplateNest) Render(toRender interface{}) (string, error) {
replacement := ""
if value, exists := v[variable.Name]; exists {
if text, ok := value.(string); ok {
replacement = text
} else {
subRender, err := nest.Render(value)
if err != nil {
return "", err
}
replacement = subRender
subRender, err := nest.Render(value)
if err != nil {
return "", err
}
if nest.option.FixedIndent && variable.IndentLevel != 0 {
indentReplacement := "\n" + strings.Repeat(" ", int(variable.IndentLevel))
subRender = strings.ReplaceAll(subRender, "\n", indentReplacement)
}
replacement = subRender
}
// Replace in rendered template

@ -0,0 +1,92 @@
package tests
import (
"git.virtual.blue/tomgracey/template-nest-go"
"github.com/stretchr/testify/assert"
"testing"
)
func TestRenderSimplePageWithFixedIndent(t *testing.T) {
nest, err := templatenest.New(templatenest.Option{
TemplateDir: "templates",
FixedIndent: true,
})
if err != nil {
t.Fatalf("Failed to initialize TemplateNest: %+v", err)
}
page := templatenest.Hash{
"TEMPLATE": "00-simple-page",
"variable": "Simple Variable",
"simple_component": templatenest.Hash{
"TEMPLATE": "02-simple-component-multi-line",
},
}
outputPage := templatenest.Hash{"TEMPLATE": "output/07-simple-page-fixed-indent"}
render := nest.MustRender(page)
outputRender := nest.MustRender(outputPage)
assert.Equal(t, outputRender, render, "Rendered output does not match expected output")
}
func TestRenderComplexPageWithFixedIndent(t *testing.T) {
nest, err := templatenest.New(templatenest.Option{
TemplateDir: "templates",
FixedIndent: true,
})
if err != nil {
t.Fatalf("Failed to initialize TemplateNest: %+v", err)
}
page := templatenest.Hash{
"TEMPLATE": "10-complex-page",
"title": "Complex Page",
"pre_body": templatenest.Hash{
"TEMPLATE": "18-styles",
},
"navigation": templatenest.Hash{
"TEMPLATE": "11-navigation",
"banner": templatenest.Hash{
"TEMPLATE": "12-navigation-banner",
},
"items": []templatenest.Hash{
templatenest.Hash{"TEMPLATE": "13-navigation-item-00-services"},
templatenest.Hash{"TEMPLATE": "13-navigation-item-01-resources"},
},
},
"hero_section": templatenest.Hash{
"TEMPLATE": "14-hero-section",
},
"main_content": []templatenest.Hash{
templatenest.Hash{"TEMPLATE": "15-isdc-card"},
templatenest.Hash{
"TEMPLATE": "16-vb-brand-cards",
"cards": []templatenest.Hash{
templatenest.Hash{
"TEMPLATE": "17-vb-brand-card-00",
"parent_classes": "p-card brand-card col-4",
},
templatenest.Hash{
"TEMPLATE": "17-vb-brand-card-01",
"parent_classes": "p-card brand-card col-4",
},
templatenest.Hash{
"TEMPLATE": "17-vb-brand-card-02",
"parent_classes": "p-card brand-card col-4",
},
},
},
},
"post_footer": templatenest.Hash{
"TEMPLATE": "19-scripts",
},
}
outputPage := templatenest.Hash{"TEMPLATE": "output/08-complex-page-fixed-indent"}
render := nest.MustRender(page)
outputRender := nest.MustRender(outputPage)
assert.Equal(t, outputRender, render, "Rendered output does not match expected output")
}