The yst package
yst is a tool for generating a static website
by filling string templates with data taken from
YAML text files (or, alternatively, CSV files).
This approach combines the speed, security, and
ease of deployment of a static website with the
flexibility and maintainability of a dynamic site
that separates presentation and data.
[Skip to Readme]
|Versions||0.1, 0.2, 0.2.1, 0.2.2, 0.2.2.1, 0.2.3, 0.2.3.1, 0.2.3.2, 0.2.4, 0.2.4.1, 0.3, 0.3.0.1, 0.3.1, 0.3.1.1, 0.3.1.2, 0.4, 0.4.0.1, 0.4.1, 0.4.1.1, 0.5, 0.5.0.1, 0.5.0.2, 0.5.0.3, 0.5.0.4, 0.5.1, 0.5.1.1|
|Dependencies||base (>=3 && <5), containers, csv, directory, filepath, HsSyck, HStringTemplate (>=0.6.1), old-locale, old-time, pandoc, parsec, time, utf8-string, xhtml [details]|
|Uploaded||Sat Aug 1 18:19:30 UTC 2009 by JohnMacFarlane|
|Downloads||4535 total (26 in the last 30 days)|
|Status||Docs not available [build log]
All reported builds failed as of 2016-12-31 [all 8 reports]
Hackage Matrix CI
For package maintainers and hackage trustees
Readme for yst
Readme for yst-0.1
yst - static websites from YAML and string templates
yst is a tool for generating a static website by filling string
templates with data taken from YAML or CSV text files. This approach
combines the speed, security, and ease of deployment of a static
website with the flexibility and maintainability of a dynamic site that
separates presentation and data.
yst is written in Haskell. The easiest way to install
yst is by using
Haskell's cabal install tool. The best way to get this tool is to
install the Haskell platform, which includes a complete installation
of the [GHC] compiler and the
Once you have
cabal, you can install yst with two commands:
cabal update cabal install yst
(Note that by default,
cabal installs the
yst executable into
a special directory:
~\.cabal\bin on unix systems. You will need
to make sure that directory is in your system path.)
To get started with
yst, use the command:
yst create mysite
This will create a directory
mysite and populate it with the files
needed for a sample site. Change to this directory and run
no arguments to create the site:
cd mysite yst
The site will be created in the
site directory. Open up
to take a look.
The configuration file
yst which pages to build,
and from which templates and data files. Let's take a look, so we can see
what went into
index.html. The file is a YAML list of YAML hashes
(name/value pairs). The first item is
- url : index.html title : Home template : index.st requires : event.st data : recentevents : events.yaml ORDER BY date DESC LIMIT 2
This says: build the page
index.html from the string template
event.st) and data from
events.yaml. Sort this data
(a list of events) by date in descending order, and discard all but the
first two items. Put the resulting data in the string template attribute
recentevents. Give the page the title "Home."
Now take a look at
events.yaml, the data source. Again it is a YAML
list of YAML hashes, each item in the list representing one event.
The first is:
- date: 2009-06-28 speaker: Sam Smith title: Building a static website
Pretty self-explanatory! Try adding a new event, then rebuild the
site by typing
yst and see how it looks.
If you have problems, make sure
events.yaml is a valid YAML file.
Structure is shown through indentation, so make sure things line
up right. And occasionally you may need to use quotation marks
around string values---for example, when a title contains a colon.
There's one more ingredient in our recipe---the string templates.
Take a look at
index.st, the template from which
# Welcome Here's our website. Have a look around. Our last two events: $recentevents:event()$ For a complete list of events, see the [events](events.html) page.
The first thing to notice is that this is in markdown format (or, to be precise, markdown with pandoc extensions). So, for example, the first line is a level-one header, and there is a hyperlink to the events page on the last line.
The second thing to notice is the bit between dollar signs.
This is a placeholder for some formatted data. The rendered
template will include the list
recentevents (remember, this
was populated from
events.yaml after some transformations---see
above). And each element of this list will be formatted by
a subtemplate called
- $if(it.speaker)$$it.speaker; separator=" and "$, $endif$ *$it.title$*.
Let's break this down. The whole line will print a bulleted list
it here refers to the event that is being processed by the
template. So the first part says: if this event has a
print the speaker, or, if the
speaker field is a list, print all the
speakers separated by the word "and", followed by a comma. And the
second part says, print the contents of the
title field, surrounding
it with asterisks (which is the markdown way of making it emphasized).
(See the string template documentation for details of template syntax, and examples.)
If you look at
index.html, you'll see this rough structure, but in
an HTML file, not a markdown file.
yst converts the rendered markdown
template to HTML (using pandoc), and inserts it into a "layout" file
layout.html.st. If you look at this file, you'll see that it's
an HTML file with blanks for
blank gets filled by the rendered template, converted to HTML, and
$nav$ blank gets filled by an HTML navigation menu (an unordered
list with links).
To summarize our example, then:
yst sorts and filters the data in
events.yaml according to our instructions; inserts this data into
events.st template, formatting each item using the
template; uses pandoc to convert the rendered template to HTML;
constructs a navigation menu; and puts the contents and navigation
menu in the layout template
layout.html.st. The result is our page,
yst # rebuilds site, using default config.yaml yst -f myconf.yaml # rebuilds site, using myconf.yaml as config yst create newsite # creates a starter (demo) site in newsite directory
When run without arguments,
yst looks at
index.yaml to determine
the dependencies of each page, and rebuilds only the pages whose
dependencies have changed since the last build.
In order for this to work properly, you must be sure to list all
subtemplates included recursively in the main page template using
requires field. This field takes a single filename or a
YAML list, which may be in either of two formats:
requires: [event.st, date.st]
requires: - event.st - date.st
If you don't list all the subtemplates needed to render a page
yst will still work, but it might sometimes
fail to rebuild a page when one of these subtemplates has been changed.
The configuration file specifies the following:
indexfile: the filename of the index file (default:
title: the title of the whole site
templatedir: the directory containing templates (default:
datadir: the directory containing yaml data files (default:
filesdir: the directory containing static files (default:
layout: the default layout template for the site (default:
index.yaml and submenus
The index file is a YAML list of pages. Each page may have the following fields:
url: the relative URL of the page to be built
title: the title of the page
template: the main string template from which the page will be built
source: the markdown source from which the page will be built
requires: other files changes to which should trigger a page rebuild (primarily subtemplates of the main page template)
data: string template attributes, data sources, and transformations (see below)
layout: a layout template to use, if other than the site default
inmenu: if 'no', the page will not be included in the site navigation menu
Each page must have at least
title, and either
The pages may be organized into a tree-like hierarchy, which will be reflected in the site navigation menu. It is easiest to see how this works by example:
- Rooms: - url : room101.html title : Room 101 source : room101.txt - url : room203.html title : Room 203 source : room203.txt
Here we have a subtree called "Rooms" with two pages under it. Subtrees can contain other subtrees. Just be consistent about indentation.
data field in
index.yaml can populate any number of stringtemplate
attributes with data from YAML or CSV files. The syntax is easiest to
explain by example (note that the keywords do not have to be in ALL CAPS,
although they may, and the query doesn't have to end with a semicolon,
though it may):
data: events: events.yaml order by date desc group by title then location people: people.csv order by birthday then lastname where birthstate = 'CA' limit 5
First we have the name of the stringtemplate attribute to be populated
events). Then, after the colon, we have the data source
events.yaml) followed by one or more transformations, which will
be applied in order. Here are the possible transformations. In
what follows, brackets denote an optional component,
* indicates that the component may be repeated
ORDER BY field [ASC|DESC] [THEN field [ASC|DESC]]*
Sorts a list by comparing the value of
(the default) means "ascending", and `DESC` means "descending". The keyword `THEN` is used to separate fields that will be compared in order. So, if we are ordering by `birthday then lastname`, we will compare birthdays, and if these are equal, we will break the tie by comparing last names.
GROUP BY field [THEN field]*
Converts a list into a list of lists, where each sublist contains
only items with the same value for `field`. So, for example, `group by date` takes a list of events and produces a list of lists of items, where each sublist contains events occuring at a single date. `GROUP BY date THEN venue` would produce a list of lists of lists, and so on.
Removes all but the n top items from a list. n must be a number.
Selects only items that meet a condition.
A condition in a
WHEREstatement is a Boolean combination (using
`NOT`, `AND`, `OR`, and parentheses for disambiguation) of *basic conditions*. A *basic condition* is of the form `value op value`, where `value` may be either a fieldname or a constant. Note that all constants must be enclosed in quotes. `op` may be one of the following: `=`, `>=`, `<=`, `>`, `<`.
Note that the order of transformations is significant. You can get
different results if you use
LIMIT before or after
Any file or subdirectory in the
files directory (or whatever is
the value of
config.yaml) will be copied verbatim to
PDFs, and the like.
yst will recognize date fields in data files automatically, if the
dates are in one of the following formats:
- the locale's standard date format - MM/DD/YYYY (e.g. 04/28/1953) - MM/DD/YY (e.g. 04/28/53) - YYYY-MM-DD (e.g. 1953-04-28) - DD MON YYYY (e.g. 28 Apr 1953)
Dates may be formatted in templates using a stringtemplate "format"
directive. There's an example in the demo file
$it; format="%B %d, %Y"$
The following codes may be used in format strings (taken from
%D: same as
%F: same as
%x: as dateFmt locale (e.g.
%y: last two digits of year, 00 - 99
%C: century (being the first two digits of the year), 00 - 99
%B: month name, long form (fst from months locale), January - December
%b, %h: month name, short form (snd from months locale), Jan - Dec
%m: month of year, leading 0 as needed, 01 - 12
%d: day of month, leading 0 as needed, 01 - 31
%e: day of month, leading space as needed, 1 - 31
%j: day of year for Ordinal Date format, 001 - 366
%G: year for Week Date format
%g: last two digits of year for Week Date format, 00 - 99
%f: century (first two digits of year) for Week Date format, 00 - 99
%V: week for Week Date format, 01 - 53
%u: day for Week Date format, 1 - 7
%a: day of week, short form (snd from wDays locale), Sun - Sat
%A: day of week, long form (fst from wDays locale), Sunday - Saturday
%U: week number of year, where weeks start on Sunday (as sundayStartWeek), 00 - 53
%w: day of week number, 0 (= Sunday) - 6 (= Saturday)
%W: week number of year, where weeks start on Monday (as mondayStartWeek), 00 - 53
Lists as values
In some cases, a field may have one or several values. For example, an event might occur at a date or a date range, and an article may have one author or a list of authors.
An elegant way to handle these cases is to let the field take either a
scalar or a list value, and use stringtemplate's "separator" directive
to format the result appropriately. So, for example, in our
- date: 2009-06-28 speaker: Sam Smith title: Building a static website - date: 2009-04-15 speaker: - Sam Smith - '[Jim Jones](http://foo.bar/baz)' title: Advantages of static websites - date: - 2009-04-20 - 2009-04-22 title: Seminar on web security - date: 2009-04-15 speaker: Jim Jones title: XSS attacks for dummies
Note that the
date field is sometimes a single date, sometimes a
list (with start and end date of a range), and the
speaker field is
sometimes a single speaker, and sometimes a range.
Here is how we handle the date in
**$first(it).date:date(); separator=" - "$**
first(it).date is the raw data, which may be a single date
or a list.
first(it).date:date() is the result of formatting each
date using the
date.st template (discussed above). And
first(it).date:date; separator=" - " is the result of taking this
list of formatted dates and concatenating them, separated by a hyphen.
When there is just one date, we just get a date. When there are two,
we get a date range.
We can use the same trick in the case of
an event record, then
it.speaker; separator=" and " will be
either a single speaker (if the value is not a list) or a list
of speakers separated by "and" (if it is a list).
In sorting lists with
yst compares two lists by
comparing the first members, then (in case of a tie) the second
members, and so on. If one item is a list and the other a scalar,
the scalar is compared to the first item of the list. So, in
the example above,
Seminar on web security will be sorted
an earlier than an event with date
2009-04-21, and later than
an event with date range
2009-04-20 - 2009-04-21.
If you have a colon in a YAML value, be sure to enclose it in quotes, or you'll get an error. So,
title: "Cheever: A Life"
title: Cheever: A Life
Or (especially if the string is long), use
| for a wrapped
or unwrapped multiline string literal:
title: | A very long string that goes on and on. You can even have blank lines, but be sure to maintain indentation.
Using CSV files instead of YAML
If you like, you can use a CSV file instead of YAML for your data source.
Just give it the extension
index.yaml, you'd have:
data: events: events.csv order by date desc
This can be handy if you're using existing data, because spreadsheets and databases can easily be dumped to CSV. In the case of a SQL database, you can use a query like this to get the CSV:
SELECT * INTO OUTFILE 'result.csv' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n' FROM my_table;
Using HTML in the templates
Markdown allows raw HTML to be used, so you can embed HTML in templates.
Pandoc's extended markdown is different from standard markdown in that
it parses text within HTML block elements as markdown. So, for example,
you can include a section in
<div> tags, or use raw
tags instead of markdown formatting.
Sometimes you want to create a span-level template---something like
date.st, which just formats a date:
$it; format="%B %d, %Y"$
If you create a file containing this line with a regular text editor, the file will end with a newline character. This will be treated as a newline in the template, so you'll get a new line after every date in a list of dates: not what you want.
The solution is to set up your text editor so that it doesn't
add the newline at the end of the file. Using vim, you can do this
with the commands
set binary and
set noeol. To make this the
.st files, add this line to
au! BufRead,BufNewFile *.st setfiletype stringtemplate
Then add a file
the following contents:
set binary set noeol
Layout files are also string templates, but they are not treated as
markdown by default. They should use a double extension to indicate
the format. So, for example, an HTML layout could be
and a LaTeX layout could be
yst will convert the
page contents appropriately for the format of the layout template.
Here are the supported formats and extensions:
- Groff man:
- Rich text format:
- OpenDocument XML:
- Plain text (markdown):
The demo site shows how you can use
yst to produce a LaTeX document
from the same data sources you use to produce HTML pages.
The following stringtemplate attributes are defined when layouts are rendered:
$contents$: the result of rendering the page and converting to the layout's format
$nav$: an HTML navigation menu created from
$gendate$: the date the page was generated
$sitetitle$: the site title from
$pagetitle$: the page title as defined in