loom/docs/interpolation.md

3.4 KiB

Interpolation

In Loom, interpolation refers to the process of modifying text values in an abstract syntax tree (AST) by applying data held in scope in code to the strings.

The mechanism provided by loom for these interpolations are the interpolate*() functions:

interpolate: tree, node, string, value, object, array

Interpolation data

The most simple interface to interpolation is using a context mask. See that section for more details.

Context

As you traverse a tree or subtree of nodes, you can assign data to the node for later interpolation. This data is called the node's context. Each node's context is stored in its .data.context property. Note that the Unified.js AST convention provides the .data property and other things may modify its contents. Use .data.context for a safe place to store the node's data for interpolation purposes.

When a node is processed, it gets sees the context of all of its parents. Nearer contexts shadow farther contexts. This works in the same way that shadowing works in JavaScript, where the innermost value is used. In JavaScript, this is seen this way:

(foo) => {
	let a = 1;
	[10,20].forEach((a) => console.log(a));
  console.log(a);
}

Notice that inside the interior function, the parent's value of a is shadowed by the child's value of a from the function's signature. This script will output:

10
20
1

In a loom AST, the functionality is very similar. Consider the following HTML AST (abbreviated for clarity):

{
	"tagName": "personal-greetings",
	data: { context: { name: "Othello" } },
	"children": [
		{
			"tagName": "p",
			"children": [
				{ type: "text", value: "Hello, ${name}!" }
			]
		},
		{
			"tagName": "p",
			data: { context: { name: "Margaret" } },
			"children": [
				{ type: "text", value: "Hello, ${name}!" }
			]
		},
	]
}

Notice that the <personal-greetings> tag has context associated with it: .data.context.nameis set to"Othello"`.

Of the two children, the former item does not have its own data, while the latter item does; it's context sets the name to "Margaret".

The code to interpolate and render the AST could look like this:

console.log(astToHtml(interpolate(tree)));

The rendered version of this AST to HTML would look like this:

<personal-greetings>
	<p>Hello, Othello!</p>
	<p>Hello, Margaret!</p>
</personal-greetings>

In the first node, name is available through the parent's context. In the second node, name is shadowed by the child's own value, "Margaret".

Context Masks

You may interpolate any value with a context mask by passing it in as a second parameter to the interpolate\*() functions.

Using the example provided in the Contexts section, you could write:

console.log(astToHtml(interpolate(tree, {name: "Samwise"})));

The rendered version of this AST to HTML would look like this:

<personal-greetings>
	<p>Hello, Samwise!</p>
	<p>Hello, Samwise!</p>
</personal-greetings>