Files
marka/renderer/renderer.go
2025-08-19 17:20:24 +02:00

79 lines
2.3 KiB
Go

// Package renderer provides functions for rendering Marka templates.
package renderer
import (
"bytes"
"encoding/json"
"fmt"
"strings"
"git.max-richter.dev/max/marka/registry"
"git.max-richter.dev/max/marka/renderer/codec"
"git.max-richter.dev/max/marka/template"
"git.max-richter.dev/max/marka/validator"
)
const emptyBlock = "\uE000"
func fixRenderedBlock(input string) string {
input = strings.ReplaceAll(input, "'@type':", "@type:")
input = strings.ReplaceAll(input, "'@context':", "@context:")
if len(input) == 0 {
return emptyBlock
}
return input
}
func RenderFile(rawJSON []byte) ([]byte, error) {
// 1) parse json
var data map[string]any
if err := json.Unmarshal(rawJSON, &data); err != nil {
return nil, fmt.Errorf("failed to parse JSON: %w", err)
}
// 2) extract type from "@type" Property
contentType, ok := data["@type"].(string)
if !ok || contentType == "" {
return nil, fmt.Errorf("JSON does not contain a valid '@type' property")
}
// 3) get the template from the registry
templateContent, err := registry.GetTemplate(contentType)
if err != nil {
return nil, fmt.Errorf("could not get template for type '%s': %w", contentType, err)
}
// 4) parse the template with the template package
compiledTemplate, err := template.CompileTemplate(templateContent)
if err != nil {
return nil, fmt.Errorf("failed to compile template for type '%s': %w", contentType, err)
}
// 5) validate JSON against schema
if schemaName, ok := data["@schema"].(string); ok {
if validationErr := validator.ValidateSchema(data, schemaName); validationErr != nil {
return nil, fmt.Errorf("failed to validate schema: %w", validationErr)
}
}
// 6) render the template with the blocks
var buffer bytes.Buffer
for _, block := range compiledTemplate {
renderedContent, err := codec.RenderBlock(block, data)
if err != nil {
return nil, fmt.Errorf("failed to render block for path '%s': %w", block.Path, err)
}
renderedContent = fixRenderedBlock(renderedContent)
buffer.WriteString(renderedContent)
}
outputString := buffer.String()
outputString = strings.ReplaceAll(outputString, "\n\n"+emptyBlock+"\n\n", "\n\n")
outputString = strings.ReplaceAll(outputString, emptyBlock, "")
if !strings.HasSuffix(outputString, "\n") {
outputString += "\n"
}
return []byte(outputString), nil
}