---
title: ytt dev notes & tech forum discussions
tags: ytt
---
Note: This is a working doc meant for writing down working ideas. Please see the [docs](https://carvel.dev/ytt) for official definitions.
Input
---
Users:
- Configuration Authors: Authors of templates and data values. In Kubernetes world, these are often application developers, devops, or PAs. The authors then distribute the templates to those that want to install/use them.
- Configuration Consumers: Consumers of the templates that the Configuration Authors wrote. In k8s world, they use the templates to install the applications onto their clusters.
Types:
- NewBulkFilesSource: Used to process JSON input, from the ytt playground
- NewRegularFilesSource: Primary input source. Processes files input with `-f` and accepts other flags.
- Directory Structure / file system contract:
- Libraries:
- Like a virtual file system built from the relative file path of the inputs. Some libraries can be 'private'.
- Private library:
- is one that is in the `_ytt_lib` directory.
- Other libraries cannot access a private library.
- It can be thought of as a separate ytt invocation.
- File Marks: Used to override the default behavior of ytt file processing. Can override the file extension.
- Data Values: Provide a way to inject input data into a template via parameterized variables.
Concepts
---
- Overlays:
- Additional templates that are merged with the previous templates. Templates and data values are merged separately.
- Left: being modified
- Right: the overlay describing the modification.
- Single unit template: Each yaml document is its own single unit. One unit can overlay another, and does not relate to scope. For other file types, a file may be a single unit of configuration.
Strive for:
---
- Readability:
- Important for new maintainers
- Descriptive & consistent variable names
- Extract code to functions when it's not helpful to have the context at the current level.
- Don't extract code to function when it does not add to complexity.
- Refactors are necessary to get here but should be done separate from features.
- "Single Point Of Truth": Goal is to not have duplicate code to reduce inconsistency and organization. Don't pay the 'complexity cost' twice.
- Compactness: the property that a design can fit inside a human being's head.
- Be different when we have a reason to be.
- Order test variables consistently across tests.
- If I remove one line/thing in the code only ONE test should fail. In other words, test only one unit per test.
:bee: :bee: :bee:
Go patterns
---
- Explicit error checks
- Discourage use of named returns generally
- generally, yes, adds work to the reader to determine what's being returned.
- when small, might be nice to use to trim
- no reason can't "document" return values with named returns (don't have to use them)
- Keep methods private by default
- this makes sense in general, however it may be worth considering what the package 'api' should expose. Could the package be imported by other tools?
- Function names plurality match what they return (ie: return list, name is plural)
- Constructors start with 'New'
(not yet discussed) ytt patterns
---
- library patterns
- A file (schema or data value) uses it's `libRef` to indicate what library it belongs to. No libRef? Then it's intented for the current library.
- A private library is mostly 'self contained' and can be thought of as a separate ytt invocation.
- Many of data value and schema code follows a similar pattern.. Is this the goal or an intermediate stage?
- Factory
- LibraryExecutionFactory
- Envelope
- DocumentSchemaEnvelope
- Parameterized tests
- yamltemplate package: tests that can be in a single file. Similar to e2e tests, asserts on output. (used for overlays, ytt starlark addtions, file positions via `--output`)
- TestSchema_With_fuzzed_inputs ?
AST Structures
---
What is it?
* Composite of the node
* tree structure
* A scalar isn't a Node, it's the value of a Node
How're they created?
* how do they go from bytes to ast?
* Scalar types are parsed using our forked yamlv2 parser
* workspace package templateloader.go -> ParseYAML()
* yamlmeta package document_set.go -> NewDocumentSetFromBytes() unstructured data becomes structured data
* parser.go -> ParseBytes() -> parseBytes()
* Decode() yields raw yaml structures (no annotations yet)
* yaml.v2 package yaml.go unmarshals the data
* yaml.v2 defines a struct that represents the structure of the type and the decoder parses based on that
* out is what we write the value to
* n is the data we're decoding
* yamlmeta package parser.go -> parser()
* output is either a map, with map items or array with array items
* we use a mapSlice instead of a map to preserve map ordering
* assignMetas() takes yaml comments and converts to metas
* comments directly to the left of a node OR comments directly after a node are added to the node as meta
* We check that a map items' value is null if it is followed by #@ value
* Since yaml.v2 does not set the position of maps, we manually set the position of a map to the position of its parent
Do they contain scalars?
* Yes, but not as a separate node.
* They are stored in the value of where they are contained, (ie. Document, MapItem, and ArrayItem)this is where they get their position as well.
* Scalars implement the TypeWithValues interface, which has a GetPosition() function.
What do they store?
* Positions
* GetValues returns the children
* metas
How are they output?
### Representation of a computed node value:
```yaml=
---
foo:
- { a: null } #@ 41+1
```
```
doc
-> map
-> mapitem("foo")
-> array
[0] map
-> mapitem("bar")
value: null
meta: "@ 41+1"
```