parse

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: May 13, 2021 License: Apache-2.0 Imports: 11 Imported by: 0

Documentation

Overview

Package parse builds parse trees for templates as defined by text/template and html/template. Clients should use those packages to construct templates rather than this one, which provides shared internal data structures not intended for general use.

Index

Constants

This section is empty.

Variables

View Source
var DefaultsFile string
View Source
var KnownTextNodeSubstitutions map[string]string
View Source
var ReplaceWithSnakeCase bool

Functions

func IsEmptyTree

func IsEmptyTree(n Node) bool

IsEmptyTree reports whether this tree (node) is empty of everything but space.

func Parse

func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (map[string]*Tree, error)

Parse returns a map from template name to parse.Tree, created by parsing the templates described in the argument string. The top-level template will be given the specified name. If an error is encountered, parsing stops and an empty map is returned with the error.

func SubstituteSnakeCaseDefaultValue

func SubstituteSnakeCaseDefaultValue(field, snakeField string)

Substitute field with snakeField within defaults/main.yaml.

Types

type ActionNode

type ActionNode struct {
	NodeType
	Pos

	Line int       // The line number in the input. Deprecated: Kept for compatibility.
	Pipe *PipeNode // The pipeline in the action.
	// contains filtered or unexported fields
}

ActionNode holds an action (something bounded by delimiters). Control actions have their own nodes; ActionNode represents simple ones such as field evaluations and parenthesized pipelines.

func (*ActionNode) Copy

func (a *ActionNode) Copy() Node

func (*ActionNode) String

func (a *ActionNode) String() string

type BoolNode

type BoolNode struct {
	NodeType
	Pos

	True bool // The value of the boolean constant.
	// contains filtered or unexported fields
}

BoolNode holds a boolean constant.

func (*BoolNode) Copy

func (b *BoolNode) Copy() Node

func (*BoolNode) String

func (b *BoolNode) String() string

type ChainNode

type ChainNode struct {
	NodeType
	Pos

	Node  Node
	Field []string // The identifiers in lexical order.
	// contains filtered or unexported fields
}

ChainNode holds a term followed by a chain of field accesses (identifier starting with '.'). The names may be chained ('.x.y'). The periods are dropped from each ident.

func (*ChainNode) Add

func (c *ChainNode) Add(field string)

Add adds the named field (which should start with a period) to the end of the chain.

func (*ChainNode) Copy

func (c *ChainNode) Copy() Node

func (*ChainNode) String

func (c *ChainNode) String() string

type CommandNode

type CommandNode struct {
	NodeType
	Pos

	Args          []Node // Arguments in lexical order: Identifier, field, or constant.
	IsFunc        bool   // Whether the CommandNode represents a function invocation.
	PipeNodeCount int    // The number of pipe invocations.
	// contains filtered or unexported fields
}

CommandNode holds a command (a pipeline inside an evaluating action).

func (*CommandNode) Copy

func (c *CommandNode) Copy() Node

func (*CommandNode) SetIsFunc

func (c *CommandNode) SetIsFunc() *CommandNode

func (*CommandNode) String

func (c *CommandNode) String() string

type DotNode

type DotNode struct {
	NodeType
	Pos
	// contains filtered or unexported fields
}

DotNode holds the special identifier '.'.

func (*DotNode) Copy

func (d *DotNode) Copy() Node

func (*DotNode) String

func (d *DotNode) String() string

func (*DotNode) Type

func (d *DotNode) Type() NodeType

type FieldNode

type FieldNode struct {
	NodeType
	Pos

	Ident []string // The identifiers in lexical order.
	// contains filtered or unexported fields
}

FieldNode holds a field (identifier starting with '.'). The names may be chained ('.x.y'). The period is dropped from each ident.

func (*FieldNode) Copy

func (f *FieldNode) Copy() Node

func (*FieldNode) String

func (f *FieldNode) String() string

type IdentifierNode

type IdentifierNode struct {
	NodeType
	Pos

	Ident  string // The identifier's name.
	IsFunc bool   // whether the IdentifierNode represents a text/template function
	// contains filtered or unexported fields
}

IdentifierNode holds an identifier.

func NewIdentifier

func NewIdentifier(ident string) *IdentifierNode

NewIdentifier returns a new IdentifierNode with the given identifier name.

func (*IdentifierNode) Copy

func (i *IdentifierNode) Copy() Node

func (*IdentifierNode) SetIsFunc

func (i *IdentifierNode) SetIsFunc() *IdentifierNode

Sets a hint in the IdentifierNode that the underlying Identifier is a function.

func (*IdentifierNode) SetPos

func (i *IdentifierNode) SetPos(pos Pos) *IdentifierNode

SetPos sets the position. NewIdentifier is a public method so we can't modify its signature. Chained for convenience. TODO: fix one day?

func (*IdentifierNode) SetTree

func (i *IdentifierNode) SetTree(t *Tree) *IdentifierNode

SetTree sets the parent tree for the node. NewIdentifier is a public method so we can't modify its signature. Chained for convenience. TODO: fix one day?

func (*IdentifierNode) String

func (i *IdentifierNode) String() string

type IfCommandNode

type IfCommandNode struct {
	NodeType
	Pos

	Args []Node // Arguments in lexical order: Identifier, field, or constant.
	// contains filtered or unexported fields
}

IfCommandNode holds a command (a pipeline inside an "if" statement). Since

func (*IfCommandNode) Copy

func (c *IfCommandNode) Copy() Node

func (*IfCommandNode) String

func (c *IfCommandNode) String() string

type IfNode

type IfNode struct {
	NodeType
	Pos

	Line     int         // The line number in the input. Deprecated: Kept for compatibility.
	Pipe     *IfPipeNode // The pipeline to be evaluated.
	List     *ListNode   // What to execute if the value is non-empty.
	ElseList *ListNode   // What to execute if the value is empty (nil if absent).
	// contains filtered or unexported fields
}

IfNode is the representation of a "if" statement. This is a tailored version of text/template's BranchNode. The text/template package "if", "for" and "with" utilizing the BranchNode abstraction. This makes sense, since the types are all very similar in Go Templating, and they are all output in very similar manners. However, Jinja2 has greater requirements surrounding output of these Branch structures. This abstraction is introduced to handle the "if" BranchNode.

Currently, the implementation makes a best guess to fully translate "if" conditionals. There is not always a deterministic conversion, which is discussed in much greater detail below. However, this implementation makes a best attempt approach to resolve a proper translation. There are two major difference between Go Template conditionals and Jinja2 conditionals:

1. If-Ambiguity: In Go template language, a conditional such as "{{ if something }}" is overloaded and may mean:

"if something is true" (boolean evaluation) or "if something is defined" (definition check)

Jinja2 does not support this overloaded conditional evaluation behavior.  There is no deterministic way to tell
whether an arbitrary condition is expressing boolean evaluation or checking for definition without further
information.  Thus, a heuristic is introduced to make a best guess.  The input Helm Chart's Values.yaml file is
interrogated for the "something" key.  If "something" exists and its value is a boolean, then the conditional is
classified as boolean evaluation, and will output as:

{% if something %}

Otherwise, if the key is not found or the value is not a boolean, then the conditional is classified as a
definition check.  In this case, the Jinja2 output is:

{% if something is defined %}

Note:  You must uncomment optional configuration in order for this heuristic to work accurately.
  1. Boolean-Composition: Go Template language treats boolean operators ("and", "or", "not") as function calls. Thus, the syntax is "<booleanOperator> <condition1> <condition2>". Treating such operators as function invocations is a common tactic in language development, as it significantly reduces the complexity of the parser. However, Jinja2 treats boolean operators in a more traditional way, and expects the syntax "<condition1> <booleanOperator> <condition2>". Additionally, Go template language implements an "eq" equality operator, which works in a similar way to the Go template boolean operator implementation. In these cases, the Abstract Syntax Tree nodes must be re-ordered in order to output proper Jinja2. The "swapping" of nodes in memory is necessary since these statements can, and often are, heavily nested.

func (*IfNode) Copy

func (n *IfNode) Copy() Node

func (*IfNode) String

func (n *IfNode) String() string

type IfPipeNode

type IfPipeNode struct {
	NodeType
	Pos

	Line     int
	IsAssign bool
	Decl     []*VariableNode // Kept for backwards compatibility.  Since PipeNode was once overloaded to mean several
	// things, declarations were optional (i.e., "range").
	Cmds []*IfCommandNode // Commands for "if" statements are now of type IfCommandNode, which has greater
	// contains filtered or unexported fields
}

IfPipeNode holds an "if" pipeline (i.e., everything after "{{ if "). IfPipeNode was abstracted from the generic PipeNode in order to hand tailor Jinja2 output, which varies greatly from other branch structures in the Jinja2 template language.

func (*IfPipeNode) Copy

func (p *IfPipeNode) Copy() Node

func (*IfPipeNode) CopyPipe

func (p *IfPipeNode) CopyPipe() *IfPipeNode

func (*IfPipeNode) String

func (p *IfPipeNode) String() string

type ListNode

type ListNode struct {
	NodeType
	Pos

	Nodes []Node // The element nodes in lexical order.
	// contains filtered or unexported fields
}

ListNode holds a sequence of nodes.

func (*ListNode) Copy

func (l *ListNode) Copy() Node

func (*ListNode) CopyList

func (l *ListNode) CopyList() *ListNode

func (*ListNode) String

func (l *ListNode) String() string

type NilNode

type NilNode struct {
	NodeType
	Pos
	// contains filtered or unexported fields
}

NilNode holds the special identifier 'nil' representing an untyped nil constant.

func (*NilNode) Copy

func (n *NilNode) Copy() Node

func (*NilNode) String

func (n *NilNode) String() string

func (*NilNode) Type

func (n *NilNode) Type() NodeType

type Node

type Node interface {
	Type() NodeType
	String() string
	// Copy does a deep copy of the Node and all its components.
	// To avoid type assertions, some XxxNodes also have specialized
	// CopyXxx methods that return *XxxNode.
	Copy() Node
	Position() Pos // byte position of start of node in full original input string
	// contains filtered or unexported methods
}

A Node is an element in the parse tree. The interface is trivial. The interface contains an unexported method so that only types local to this package can satisfy it.

type NodeType

type NodeType int

NodeType identifies the type of a parse tree node.

const (
	NodeText      NodeType = iota // Plain text.
	NodeAction                    // A non-control action such as a field evaluation.
	NodeBool                      // A boolean constant.
	NodeChain                     // A sequence of field accesses.
	NodeCommand                   // An element of a pipeline.
	NodeIfCommand                 // An element of an IfPipeline
	NodeDot                       // The cursor, dot.

	NodeField      // A field or method name.
	NodeIdentifier // An identifier; always a function name.
	NodeIf         // An if action.
	NodeList       // A list of Nodes.
	NodeNil        // An untyped nil constant.
	NodeNumber     // A numerical constant.
	NodePipe       // A pipeline of commands.
	NodePipeRange  // A pipeline of range commands.
	NodePipeWith   // A pipeline of with commands.
	NodePipeIf     // A pipeline of if commands.
	NodeRange      // A range action.
	NodeString     // A string constant.
	NodeTemplate   // A template invocation action.
	NodeVariable   // A $ variable.
	NodeWith       // A with action.
)

func (NodeType) Type

func (t NodeType) Type() NodeType

Type returns itself andq provides an easy default implementation for embedding in a Node. Embedded in all non-trivial Nodes.

type NumberNode

type NumberNode struct {
	NodeType
	Pos

	IsInt      bool       // Number has an integral value.
	IsUint     bool       // Number has an unsigned integral value.
	IsFloat    bool       // Number has a floating-point value.
	IsComplex  bool       // Number is complex.
	Int64      int64      // The signed integer value.
	Uint64     uint64     // The unsigned integer value.
	Float64    float64    // The floating-point value.
	Complex128 complex128 // The complex value.
	Text       string     // The original textual representation from the input.
	// contains filtered or unexported fields
}

NumberNode holds a number: signed or unsigned integer, float, or complex. The value is parsed and stored under all the types that can represent the value. This simulates in a small amount of code the behavior of Go's ideal constants.

func (*NumberNode) Copy

func (n *NumberNode) Copy() Node

func (*NumberNode) String

func (n *NumberNode) String() string

type PipeNode

type PipeNode struct {
	NodeType
	Pos

	Line     int             // The line number in the input. Deprecated: Kept for compatibility.
	IsAssign bool            // The variables are being assigned, not declared.
	Decl     []*VariableNode // Variables in lexical order.
	Cmds     []*CommandNode  // The commands in lexical order.
	// contains filtered or unexported fields
}

PipeNode holds a pipeline with optional declaration

func (*PipeNode) Copy

func (p *PipeNode) Copy() Node

func (*PipeNode) CopyPipe

func (p *PipeNode) CopyPipe() *PipeNode

func (*PipeNode) String

func (p *PipeNode) String() string

type Pos

type Pos int

Pos represents a byte position in the original input text from which this template was parsed.

func (Pos) Position

func (p Pos) Position() Pos

type RangeNode

type RangeNode struct {
	NodeType
	Pos

	Line     int            // The line number in the input. Deprecated: Kept for compatibility.
	Pipe     *RangePipeNode // The pipeline to be evaluated.
	List     *ListNode      // What to execute if the value is non-empty.
	ElseList *ListNode      // What to execute if the value is empty (nil if absent).
	// contains filtered or unexported fields
}

RangeNode is the representation of a "range" statement. This is a tailored version of text/template's BranchNode. The text/template package "if", "for" and "with" utilizing the BranchNode abstraction. This makes sense, since the types are all very similar in Go Templating, and they are all output in very similar manners. However, Jinja2 has greater requirements surrounding output of these Branch structures. This abstraction is introduced to handle the "range" BranchNode.

Currently, the implementation outputs range statements using Ansible for-statement equivalents. For example, given the list-range input:

{{ range list }}

The translation is:

{% for item_list in list %}

Go Template language also supports range over maps. For the given map-range input:

{{ range $key, $value := someDict }}

The translation is:

{% for key, value in someDict.iterItems() %}

Lastly, in the case of list-range input, Go Template language implies an iterator. That is, you can access properties of the list using the member access operator ".". For example:

{{ range computerList }} {{ .ipAddress }} {{ end }}

The RangeNode implementation addresses this by appending the iterator variable name. The translation is:

{% for item_computerList in computerList %} {{ item_computerList.ipAddress }} {% endfor %}

func (*RangeNode) Copy

func (r *RangeNode) Copy() Node

func (*RangeNode) GetRangeUseCaseType

func (r *RangeNode) GetRangeUseCaseType() RangeUseCaseType

GetRangeUseCaseType ... get difference cases for range flow

func (*RangeNode) RemoveVarPrefix

func (r *RangeNode) RemoveVarPrefix(prefix string)

func (*RangeNode) String

func (r *RangeNode) String() string

type RangePipeNode

type RangePipeNode struct {
	NodeType
	Pos

	Line     int
	IsAssign bool
	Decl     []*VariableNode
	Cmds     []*CommandNode
	// contains filtered or unexported fields
}

RangePipeNode holds an "range" pipeline (i.e., everything after "{{ range "). IfPipeNode was abstracted from the generic PipeNode in order to hand tailor Jinja2 output, which varies greatly from other branch structures in the Jinja2 template language.

func (*RangePipeNode) Copy

func (p *RangePipeNode) Copy() Node

func (*RangePipeNode) CopyPipe

func (p *RangePipeNode) CopyPipe() *RangePipeNode

func (*RangePipeNode) String

func (p *RangePipeNode) String() string

type RangeUseCaseType

type RangeUseCaseType int

RangeUseCaseType identifies the types of uses cases for range.

const (
	UseCaseDefault     RangeUseCaseType = iota //Unknown use cases
	UseCaseNoVariables                         // *{{- range .Values.ingress.secrets }}
	UseCaseKeyValue                            // {{range $key, $value := ingress.annotations }}
	UseCaseSingleValue                         //{{- range $host := .Values.ingress.hosts }}
	UseCaseTuple                               //range tuple "config1.toml" "config2.toml" "config3.toml" }}
)

-------------------------------------------------------------------------------------------------------

| INPUT                                  | LHS(vars) & RHS(cmds) |  OUTPUT                              |
 --------------------------------------------------------------------------------------------------------
| *{{- range .Values.ingress.secrets }}   |       0 & 1          | {% for item_secrets in .Values.ingress.secrets }} |
----------------------------------------------------------------------------------------------------------
| {{range $key, $value := ingress.annotations }}  | 2 & 1 | {% for $key, $value in ingress.annotations %}|
-----------------------------------------------------------------------------------------------------------
| {{- range $host := .Values.ingress.hosts }}  | 1 & 1 | {% for $host in .Values.ingress.hosts }}        |
----------------------------------------------------------------------------------------------------------
| {{ range tuple "config1.toml" "config2.toml" "config3.toml" }} |0 & n |
								{% for tuple "config1.toml" "config2.toml" "config3.toml" %}

type StringNode

type StringNode struct {
	NodeType
	Pos

	Quoted string // The original text of the string, with quotes.
	Text   string // The string, after quote processing.
	// contains filtered or unexported fields
}

StringNode holds a string constant. The value has been "unquoted".

func (*StringNode) Copy

func (s *StringNode) Copy() Node

func (*StringNode) String

func (s *StringNode) String() string

type TemplateNode

type TemplateNode struct {
	NodeType
	Pos

	Line int       // The line number in the input. Deprecated: Kept for compatibility.
	Name string    // The name of the template (unquoted).
	Pipe *PipeNode // The command to evaluate as dot for the template.
	// contains filtered or unexported fields
}

TemplateNode represents a {{template}} action.

func (*TemplateNode) Copy

func (t *TemplateNode) Copy() Node

func (*TemplateNode) String

func (t *TemplateNode) String() string

type TextNode

type TextNode struct {
	NodeType
	Pos

	Text []byte // The text; may span newlines.
	// contains filtered or unexported fields
}

TextNode holds plain text.

func (*TextNode) Copy

func (t *TextNode) Copy() Node

func (*TextNode) String

func (t *TextNode) String() string

type Tree

type Tree struct {
	Name      string    // name of the template represented by the tree.
	ParseName string    // name of the top-level template during parsing, for error messages.
	Root      *ListNode // top-level root of the tree.
	// contains filtered or unexported fields
}

Tree is the representation of a single parsed template.

func New

func New(name string, funcs ...map[string]interface{}) *Tree

New allocates a new parse tree with the given name.

func (*Tree) Copy

func (t *Tree) Copy() *Tree

Copy returns a copy of the Tree. Any parsing state is discarded.

func (*Tree) ErrorContext

func (t *Tree) ErrorContext(n Node) (location, context string)

ErrorContext returns a textual representation of the location of the node in the input text. The receiver is only used when the node does not have a pointer to the tree inside, which can occur in old code.

func (*Tree) Parse

func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error)

Parse parses the template definition string to construct a representation of the template for execution. If either action delimiter string is empty, the default ("{{" or "}}") is used. Embedded template definitions are added to the treeSet map.

type VariableNode

type VariableNode struct {
	NodeType
	Pos

	Ident []string // Variable name and fields in lexical order.
	// contains filtered or unexported fields
}

AssignNode holds a list of variable names, possibly with chained field accesses. The dollar sign is part of the (first) name.

func (*VariableNode) Copy

func (v *VariableNode) Copy() Node

func (*VariableNode) String

func (v *VariableNode) String() string

type WithNode

type WithNode struct {
	NodeType
	Pos

	Line     int           // The line number in the input. Deprecated: Kept for compatibility.
	Pipe     *WithPipeNode // The *with* pipeline to be evaluated.
	List     *ListNode     // What to execute if the value is non-empty.
	ElseList *ListNode     // What to execute if the value is empty (nil if absent).
	// contains filtered or unexported fields
}

WithNode is the representation of a "with" statement. This is a tailored version of text/template's BranchNode. The text/template package "if", "for" and "with" utilizing the BranchNode abstraction. This makes sense, since the types are all very similar in Go Templating, and they are all output in very similar manners. However, Jinja2 has greater requirements surrounding output of these Branch structures. This abstraction is introduced to handle the "with" BranchNode.

Currently, the implementation outputs go template code, as Ansible does not support the "with" block. A warning including the source line number is emitted to the user that a manual conversion is required. In the future, this should be improved to support a more automated form of conversion.

func (*WithNode) Copy

func (w *WithNode) Copy() Node

func (*WithNode) String

func (w *WithNode) String() string

type WithPipeNode

type WithPipeNode struct {
	NodeType
	Pos

	Line     int
	IsAssign bool
	Decl     []*VariableNode
	Cmds     []*CommandNode
	// contains filtered or unexported fields
}

WithPipeNode holds a "with" pipeline (i.e., everything after "{{ with "). IfPipeNode was abstracted from the generic PipeNode in order to hand tailor Jinja2 output, which varies greatly from other branch structures in the Jinja2 template language.

func (*WithPipeNode) Copy

func (p *WithPipeNode) Copy() Node

func (*WithPipeNode) CopyPipe

func (p *WithPipeNode) CopyPipe() *WithPipeNode

func (*WithPipeNode) String

func (p *WithPipeNode) String() string

Jump to

Keyboard shortcuts

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