runtime

package
v0.3.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 8, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package runtime provides expression evaluation for computed expressions. Expressions are inline code spans starting with = that evaluate against source data. Example: `=count(tasks where done)` evaluates the count of done tasks.

Security Considerations

Expression evaluation operates on data from configured sources (lvt-source). This has security implications that developers should be aware of:

  • Source Access: Expressions can access any data exposed by sources defined in the page frontmatter or site config. Ensure sources only expose data appropriate for the page's audience.

  • No Code Execution: Expressions use a restricted DSL (count, sum, avg, min, max) with where clauses. They cannot execute arbitrary code or access system resources.

  • Error Messages: Parse and evaluation errors are returned to the client and displayed in the UI. Error messages should not leak sensitive information. The escapeAttr function sanitizes error text for safe HTML attribute rendering.

  • Field Access: The case-insensitive field matching (getFieldValue) allows accessing fields regardless of casing. This is intentional for usability but means field names are not access-controlled within a source.

  • No Injection: The expression parser validates syntax before evaluation. Source names and field names must match alphanumeric patterns, preventing injection attacks through expression strings.

Package runtime provides in-process state handling for lvt-source blocks, replacing the previous plugin-based compilation approach.

Index

Constants

This section is empty.

Variables

View Source
var TemplateFuncs = template.FuncMap{

	"now":       func() time.Time { return time.Now() },
	"today":     func() string { return time.Now().Format("2006-01-02") },
	"timestamp": func() string { return time.Now().Format(time.RFC3339) },
	"unix":      func() int64 { return time.Now().Unix() },

	"formatDate": formatDate,

	"add": func(a, b int) int { return a + b },
	"sub": func(a, b int) int { return a - b },
}

TemplateFuncs provides template functions for action data processing. These are used to fill in dynamic values like timestamps and dates.

Functions

func EvaluateExpressions

func EvaluateExpressions(expressions map[string]string, ctx *EvalContext) map[string]*ExprResult

EvaluateExpressions evaluates a map of expression strings. Returns a map of expression ID to result.

Types

type Arg

type Arg struct {
	Name        string `json:"name"`
	Label       string `json:"label"`
	Type        string `json:"type"`
	Description string `json:"description"`
	Required    bool   `json:"required"`
	Default     string `json:"default,omitempty"`
	Value       string `json:"value,omitempty"`
}

Arg represents an exec source argument

type DefaultResolver

type DefaultResolver struct {
	// contains filtered or unexported fields
}

DefaultResolver resolves template expressions in default values. It supports time functions and operator identity.

func NewDefaultResolver

func NewDefaultResolver(operator string) *DefaultResolver

NewDefaultResolver creates a new DefaultResolver with the given operator identity.

func (*DefaultResolver) Resolve

func (r *DefaultResolver) Resolve(value string) (interface{}, error)

Resolve processes a string value, expanding any template expressions. If the value doesn't contain template syntax, it's returned unchanged.

func (*DefaultResolver) ResolveMap

func (r *DefaultResolver) ResolveMap(data map[string]interface{}) (map[string]interface{}, error)

ResolveMap processes all string values in a map, expanding template expressions. This is used to process action data before writing.

type EvalContext

type EvalContext struct {
	// Sources maps source names to their data rows.
	Sources map[string][]map[string]interface{}
}

EvalContext provides data sources for expression evaluation.

func NewEvalContext

func NewEvalContext() *EvalContext

NewEvalContext creates a new evaluation context.

type ExprResult

type ExprResult struct {
	Value interface{}
	Error string
}

ExprResult represents the result of expression evaluation.

func (*ExprResult) Render

func (r *ExprResult) Render() string

Render returns an HTML representation of the result.

type Expression

type Expression interface {
	// Eval evaluates the expression against the given context.
	Eval(ctx *EvalContext) (interface{}, error)
}

Expression represents a parsed computed expression.

func ParseExpr

func ParseExpr(input string) (Expression, error)

ParseExpr parses an expression string into an evaluable Expression. Supported syntax:

  • count(source) - count all rows
  • count(source where field) - count rows where field is truthy
  • count(source where field = value) - count rows where field equals value
  • sum(source.field) - sum a numeric field
  • avg(source.field) - average a numeric field
  • min(source.field) - minimum value of a field
  • max(source.field) - maximum value of a field

type FuncExpr

type FuncExpr struct {
	Name   string       // count, sum, avg, min, max
	Source string       // source name (e.g., "tasks")
	Field  string       // field name for sum/avg/min/max (e.g., "amount")
	Where  *WhereClause // optional where filter
}

FuncExpr represents a function call expression.

func (*FuncExpr) Eval

func (e *FuncExpr) Eval(ctx *EvalContext) (interface{}, error)

Eval evaluates the function expression.

type GenericState

type GenericState struct {
	// Common fields (JSON-serializable for templates)
	Data   []map[string]interface{} `json:"data"`
	Error  string                   `json:"error,omitempty"`
	Errors map[string]string        `json:"errors,omitempty"`

	// Datatable field - used when source is rendered in a table element
	Table *datatable.DataTable `json:"table,omitempty"`

	// Cache metadata for UI display
	CacheInfo *cache.CacheInfo `json:"cache_info,omitempty"`

	// Inline edit state - tracks which row is being edited (empty = none)
	EditingID string `json:"editingId,omitempty"`

	// Exec-specific fields
	Output     string `json:"output,omitempty"`
	Stderr     string `json:"stderr,omitempty"`
	Duration   int64  `json:"duration,omitempty"`
	Status     string `json:"status,omitempty"`
	Command    string `json:"command,omitempty"`
	Args       []Arg  `json:"args,omitempty"`
	Executable string `json:"executable,omitempty"`
	// contains filtered or unexported fields
}

GenericState holds runtime state for any source type. It replaces the code-generated State structs that were previously compiled as plugins.

func NewGenericState

func NewGenericState(name string, cfg config.SourceConfig, siteDir, currentFile string) (*GenericState, error)

NewGenericState creates a new state for the given source configuration. This replaces the plugin compilation step - state is created directly in-process.

func NewGenericStateForComputed

func NewGenericStateForComputed(name string, cfg config.SourceConfig, siteDir, currentFile string, metadata map[string]string, sourceLookup func(string) (source.Source, bool)) (*GenericState, error)

NewGenericStateForComputed creates a state for a computed source. sourceLookup is used to resolve the parent source by name. If nil, the parent is created from config using createSource.

func NewGenericStateWithMetadata

func NewGenericStateWithMetadata(name string, cfg config.SourceConfig, siteDir, currentFile string, metadata map[string]string) (*GenericState, error)

NewGenericStateWithMetadata creates a new state with block metadata for datatable support. Metadata should include "lvt-element" ("table", "select", or "div") and "lvt-columns" for tables.

func (*GenericState) Close

func (s *GenericState) Close() error

Close releases any resources held by the source.

func (*GenericState) GetFilteredData

func (s *GenericState) GetFilteredData() []map[string]interface{}

GetFilteredData returns the data with the active filter applied. This is used by the template renderer to show filtered results. Note: This method must be called while holding at least a read lock, or from within a method that already holds the lock.

func (*GenericState) GetState

func (s *GenericState) GetState() (json.RawMessage, error)

GetState returns the current state for template rendering. This replaces the RPC GetState() call.

func (*GenericState) GetStateAsInterface

func (s *GenericState) GetStateAsInterface() (interface{}, error)

GetStateAsInterface returns the state as an interface{} for template rendering. This is used by the WebSocket handler to render templates.

func (*GenericState) HandleAction

func (s *GenericState) HandleAction(action string, data map[string]interface{}) error

HandleAction dispatches an action to the appropriate handler. This replaces the reflection-based dispatch used in generated plugins.

func (*GenericState) SetPageConfig

func (s *GenericState) SetPageConfig(actions map[string]*config.Action, registry func(string) (source.Source, bool))

SetPageConfig configures page-level settings for custom actions. actions is the map of custom actions declared in frontmatter. registry is a lookup function to find sources by name (for SQL actions).

type Store

type Store interface {
	HandleAction(action string, data map[string]interface{}) error
	// Close releases resources. Optional - returns nil if not implemented.
	Close() error
}

Store is the interface for state objects that can handle actions. All state types (GenericState for lvt-source) implement this interface.

type WhereClause

type WhereClause struct {
	Field    string      // field to filter on
	Operator string      // comparison operator: =, !=, <, >, <=, >=
	Value    interface{} // value to compare against
}

WhereClause represents a filter condition.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL