feat: renderer

This commit is contained in:
2025-08-19 17:20:24 +02:00
parent 6db87db325
commit 210b31aef8
38 changed files with 727 additions and 299 deletions

View File

@@ -1,9 +1,78 @@
// Package renderer provides functions for rendering Marka templates.
package renderer
func RenderFile(templatePath, jsonPath string) ([]byte, error) {
// TODO:
// 1) load aliases + template
// 2) validate JSON against schema (optional)
// 3) apply codecs to produce Markdown
return []byte{}, nil
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
}