HypertextLiteral is a Swift package for
generating HTML, XML, and other SGML dialects.
It uses custom string interpolation
to append and escape values based on context,
with built-in affordances for common patterns
and an extensible architecture for defining your own behavior.
import HypertextLiteral
let attributes = [
"style": [
"background": "yellow",
"font-weight": "bold"
]
]
let html: HTML = "<span \(attributes)>whoa</span>"
// <span style="background: yellow; font-weight: bold;">whoa</span>
HypertextLiteral is small and self-contained with no external dependencies.
You can get up to speed in just a few minutes,
without needing to learn any new APIs or domain-specific languages (DSLs).
Less time fighting your tools means more time spent generating web content.
This project is inspired by and borrows implementation details from
Hypertext Literal by Mike Bostock (@mbostock).
You can read more about it here.
Requirements
Swift 5.1+
Installation
Swift Package Manager
Add the HypertextLiteral package to your target dependencies in Package.swift:
Then run the swift build command to build your project.
Usage
Hypertext literals automatically escape interpolated values
based on the context in which they appear.
By default,
interpolated content escapes the XML entities<, >, &, ", and '
as named character references
(for example, < becomes <)
In the context of an attribute value,
quotation marks are escaped with a backslash (\")
In a context of comment,
any start and end delimiters (<!-- and -->) are removed
Interpolating Content
To get a better sense of how this works in practice,
consider the following examples:
let level: Int = 1
"<h\(level)>Hello, world!</h\(level)>" as HTML
// <h1>Hello, world!</h1>
let elementName: String = "h1"
"<\(elementName)>Hello, world!</\(elementName)>" as HTML
// <h1>Hello, world!</h1>
let startTag: String = "<h1>", endTag: String = "</h1>"
"\(startTag)Hello, world!\(endTag)" as HTML
// <h1>Hello, world!</h1>
Interpolation for an element’s name in part or whole work as intended,
but interpolation of the tag itself causes the string to have its
angle bracket (< and >) escaped.
When you don’t want this to happen,
such as when you’re embedding HTML content in a template,
you can either pass that content as an HTML value
or interpolate using the unsafeUnescaped argument label.
let startTag: HTML = "<h1>", endTag: HTML = "</h1>"
"\(startTag)Hello, world!\(endTag)" as HTML
// <h1>Hello, world!</h1>
"\(unsafeUnescaped: "<h1>")Hello, world!\(unsafeUnescaped: "</h1>")" as HTML
// <h1>Hello, world!</h1>
Note:
Interpolation with the unsafeUnescaped argument label
appends the provided literal directly,
which may lead to invalid results.
For this reason,
use of HTML values for composition is preferred.
Interpolating Attribute Values
Attributes in hypertext literals may be interchangeably specified
with or without quotation marks, either single (') or double (").
let id: String = "logo
let title: String = #"Swift.org | "Welcome to Swift.org""#
let url = URL(string: "https://swift.org/")!
#"<a id='\#(logo)' title="\#(title)" href=\#(url)>Swift.org</a>"# as HTML
/* <a id='logo'
title="Swift.org | \"Welcome to Swift.org\""
href="https://swift.org/">Swift.org</a>
*/
Some attributes have special, built-in rules for value interpolation.
When you interpolate an array of strings for an element’s class attribute,
the resulting value is a space-delimited list.
let classNames: [String] = ["alpha", "bravo", "charlie"]
"<div class=\(classNames)>…</div>" as HTML
// <div class="alpha bravo charlie">…</div>
If you interpolate a dictionary for the value of an element’s style attribute,
it’s automatically converted to CSS.
let style: [String: Any] = [
"background": "orangered",
"font-weight": 700
]
"<span style=\(style)>Swift</span>" as HTML
// <span style="background: orangered; font-weight: 700;">Swift</span>
The Boolean value true interpolates to different values depending the attribute.
"""
<input type="text" aria-enabled=\(true)
autocomplete=\(true)
spellcheck=\(true)
translate=\(true) />
""" as HTML
/* <input type="text" aria-enabled="true"
autocomplete="on"
spellcheck="spellcheck"
translate="yes"/> */
Interpolating Attributes with Dictionaries
You can specify multiple attributes at once
by interpolating dictionaries keyed by strings.
In addition to HTML,
you can use hypertext literals for XML and other SGML formats.
Below is an example of how HypertextLiteral can be used
to generate an SVG document.
HypertextLiteral
HypertextLiteral is a Swift package for generating HTML, XML, and other SGML dialects.
It uses custom string interpolation to append and escape values based on context, with built-in affordances for common patterns and an extensible architecture for defining your own behavior.
HypertextLiteral is small and self-contained with no external dependencies. You can get up to speed in just a few minutes, without needing to learn any new APIs or domain-specific languages (DSLs). Less time fighting your tools means more time spent generating web content.
Requirements
Installation
Swift Package Manager
Add the HypertextLiteral package to your target dependencies in
Package.swift
:Then run the
swift build
command to build your project.Usage
Hypertext literals automatically escape interpolated values based on the context in which they appear.
<
,>
,&
,"
, and'
as named character references (for example,<
becomes<
)\"
)<!--
and-->
) are removedInterpolating Content
To get a better sense of how this works in practice, consider the following examples:
Interpolation for an element’s name in part or whole work as intended, but interpolation of the tag itself causes the string to have its angle bracket (
<
and>
) escaped.When you don’t want this to happen, such as when you’re embedding HTML content in a template, you can either pass that content as an
HTML
value or interpolate using theunsafeUnescaped
argument label.Interpolating Attribute Values
Attributes in hypertext literals may be interchangeably specified with or without quotation marks, either single (
'
) or double ("
).Some attributes have special, built-in rules for value interpolation.
When you interpolate an array of strings for an element’s
class
attribute, the resulting value is a space-delimited list.If you interpolate a dictionary for the value of an element’s
style
attribute, it’s automatically converted to CSS.The Boolean value
true
interpolates to different values depending the attribute.Interpolating Attributes with Dictionaries
You can specify multiple attributes at once by interpolating dictionaries keyed by strings.
Attributes with a common
aria-
ordata-
prefix can be specified with a nested dictionary.Support for Other Formats
In addition to HTML, you can use hypertext literals for XML and other SGML formats. Below is an example of how
HypertextLiteral
can be used to generate an SVG document.License
MIT
Contact
Mattt (@mattt)