+
+
+
+
+
+
+
Warning
+
This section may contain outdated information.
+
+Leaf
+Welcome to Leaf. Leaf's goal is to be a simple templating language that can make generating views easier. There are plenty of great templating languages, so use what's best for you -- maybe that's Leaf! The goals of Leaf are:
+
+- Small set of strictly enforced rules
+- Consistency
+- Parser first mentality
+- Extensibility
+
+Syntax
+Structure
+Leaf Tags are made up of 4 Elements:
+ - Token: # is the Token
+ - Name: A string that identifies the tag
+ - Parameter List: () May accept 0 or more arguments
+ - Body (optional): {} Must be separated from the Parameter List by a space
+There can be many different usages of these 4 elements depending on the Tag's implementation. Let's look at a few examples of how Leaf's built-in Tags might be used:
+
+#()
+#(variable)
+#import("template")
+#export("link") { <a href="#()"></a> }
+#index(friends, "0")
+#loop(friends, "friend") { <li>#(friend.name)</li> }
+#raw() { <a href="#raw">Anything goes!@#$%^&*</a> }
+
+Using the # token in HTML
+The # token cannot be escaped. Use the #() or #raw() {} Tag to output a # in a Leaf Template. #() => #
+Raw HTML
+All Leaf output is escaped by default. Use the #raw() {} Tag for unescaped output.
+#raw() { <a href="#link">Link</a> } => <a href="#link">Link</a>
+
+IMPORTANT! Make sure you are not using the #raw() {} Tag with user input.
+
+Chaining
+The double token: ## indicates a chain. It can be applied to any standard Tag. If the previous Tag fails, the chained Tag will be given an opportunity to run.
+#if(hasFriends) ##embed("getFriends")
+
+
+
+
+Token: #()
+#() #()hashtags #()FTW => # #hashtags #FTW
+
+
+
+Raw: #raw() {}
+#raw() {
+ Do whatever w/ #'s here, this code won't be rendered as leaf document and is not escaped.
+ It's a great place for things like Javascript or large HTML sections.
+}
+
+
+
+Equal: #equal(lhs, rhs) {}
+#equal(leaf, leaf) { Leaf == Leaf } => Leaf == Leaf
+#equal(leaf, mustache) { Leaf == Mustache } =>
+
+
+
+Variable: #(variable)
+
+
+
+Loop: #loop(array, "item") {}
+#loop(friends, "friend") {
+ #(offset). #(friend.name)
+}
+
+
+
+The body of a #loop can access an index variable corresponding to the index of the array. There is also an offset variable which is the index plus 1.
+Index: #index(array, _ index: String)
+Hello, #index(friends, "0")!
+Hello, #index(friends, "best")!
+
+
+
+Note: array indexes are always strings.
+If - Else: #if(bool) ##else() { this }
+#if(entering) {
+ Hello, there!
+} ##if(leaving) {
+ Goodbye!
+} ##else() {
+ I've been here the whole time.
+}
+
+
+
+Note that #if requires a boolean variable. If you need to do a comparison then #equal is more appropriate. You can chain #equal in the same way as #if:
+#equal(state, "0") {
+ <span class="green">Normal</span>
+} ##equal(state, "1") {
+ <span class="orange">Warning</span>
+} ##else() {
+ <span class="red">Alert</span>
+}
+
+
+
+Import: #import("template")
+Export: #export("template") { Leaf/HTML }
+Extend: #extend("template")
+Embed: #embed("template")
+
+When using these Layout Tags, omit the template file's .leaf extension.
+
+/// base.leaf
+<!DOCTYPE html>
+#import("html")
+
+/// html.leaf
+#extend("base")
+
+#export("html") { <html>#embed("body")</html> }
+
+/// body.leaf
+<body></body>
+
+
+
+Leaf renders html.leaf as:
+<!DOCTYPE html>
+<html><body></body></html>
+
+
+
+
+Look at the existing tags for advanced scenarios, let's look at a basic example by creating Index together. This tag will take two arguments, an array, and an index to access.
+class Index: BasicTag {
+ let name = "index"
+
+ func run(arguments: [Argument]) throws -> Node? {
+ guard
+ arguments.count == 2,
+ let array = arguments[0].value?.nodeArray,
+ let index = arguments[1].value?.int,
+ index < array.count
+ else { return nil }
+ return array[index]
+ }
+}
+
+
+
+We can now register this Tag in our main.swift file with:
+if let leaf = drop.view as? LeafRenderer {
+ leaf.stem.register(Index())
+}
+
+
+
+And use it just like we did above.
+
+Note: Use of non-alphanumeric characters in Tag Names is strongly discouraged and may be disallowed in future versions of Leaf.
+
+Syntax Highlighting
+Atom
+language-leaf by ButkiewiczP
+Xcode
+It is not currently possible to implement Leaf Syntax Highlighting in Xcode, however, using Xcode's HTML Syntax Coloring can help a bit. Select one or more Leaf files and then choose Editor > Syntax Coloring > HTML. Your selected Leaf files will now use Xcode's HTML Syntax Coloring. Unfortunately the usefulness of this is limited because this association will be removed when vapor xcode is run.
+There appears to be a way to make Xcode file associations persist but that requires a bit more kung-fu.
+VS Code
+html-leaf by FranciscoAmado
+CLion & AppCode
+Some preliminary work has been done to implement a Leaf Plugin for CLion & AppCode but lack of skill and interest in Java has slowed progress! If you have IntelliJ SDK experience and want to help with this, message Tom Holland on Vapor Slack
+
+
+
+
+
+
+
+