Capy-Bearer Documentation

6. Strings and HTML

Use strings for text and HTML. A string literal and an HTML literal both yield a string value.

Escape dynamic text

<?= value ?> selects an encoding from its location. HTML text and quoted attributes escape &, <, >, quotes, and apostrophes.

function RENDER(request : dval) {
    var value := "<Ada>"
    print(<><p title="<?= value ?>"><?= value ?></p></>, "\n")
}

Output

<p title="&lt;Ada&gt;">&lt;Ada&gt;</p>

Inside a script element, a string becomes one JavaScript literal. The encoder protects the closing tag and JavaScript line separators. Inside a style element, a string becomes one CSS literal. Integer and Boolean values remain scalar values. f64 interpolation is not supported in these elements.

function RENDER(request : dval) {
    var name := string(request.query.name, {fallback: "guest"})
    print(<>
        <script>const name = <?= name ?>;</script>
        <style>.name::before { content: <?= name ?>; }</style>
    </>)
}

Script and style interpolation must start at a value boundary. Static source after it can apply an operator or a CSS unit. Do not put interpolation inside a string, template literal, or comment. Attribute values must use quotes. Tag and attribute names cannot contain interpolation.

URL, event-handler, and inline-style attributes use HTML attribute escaping. Validate these values for their application context before interpolation.

A dval cannot go directly in an HTML literal. Convert it to a string first. The name value in the previous example follows this rule.

String literals

String literals use double quotes:

function RENDER(request : dval) {
    var message := "Hello"
    var line := "first\nsecond"
    print(message, " ", line, "\n")
}

The supported escapes include \n, \r, \t, \", and \\. String positions and lengths count bytes, not Unicode characters.

Use + to join strings:

function RENDER(request : dval) {
    var name := "Ada"
    var greeting := "Hello, " + name
    print(greeting, "\n")
}

Use a constructor to convert a scalar when a function does not already accept as string:

function RENDER(request : dval) {
    var label := "Count: " + string(3)
    print(label, "\n")
}

HTML literals

An HTML literal starts with <> and ends with </>. It yields a string. Store it, pass it, return it, or print it like any other string.

function badge(label : string) string {
    -> <><strong><?= label ?></strong></>
}

function RENDER(request : dval) {
    var page := <><main><?= badge("Ready") ?></main></>
    print(page, "\n")
}

<?= value ?> escapes output at the interpolation site. The interpolation form selects escaping. The value type does not.

When one HTML literal interpolates another with <?=, the outer literal escapes the inner string. This double escape is expected. Build one final string instead of nesting HTML fragments through escaped interpolation.

function RENDER(request : dval) {
    var inner := <><em><?= "<Ada>" ?></em></>
    print(<><p><?= inner ?></p></>, "\n")
}

Output

<p>&lt;em&gt;&amp;lt;Ada&amp;gt;&lt;/em&gt;</p>

Use <?: value ?> only for source-controlled HTML text. Raw interpolation emits the string without escaping. It works only in HTML text. Do not use it for request data or other external input.

function RENDER(request : dval) {
    var fragment := "<strong>Ready</strong>"
    print(<><p><?: fragment ?></p></>, "\n")
}

Output

<p><strong>Ready</strong></p>

A dval cannot go directly in an HTML literal. Convert it with string() before <?= ?> escapes it.

function RENDER(request : dval) {
    var value := dval("<Ada>")
    print(<><p><?= string(value) ?></p></>, "\n")
}

Output

<p>&lt;Ada&gt;</p>

Common string operations

Use length, substr, find, contains, replace, lower, upper, split, and join for ordinary text work. Use html_escape when an API needs an HTML-escaped string.

Strings use automatic reference counting. Assignment and function calls preserve their lifetime. Most programs do not need to call clone.