Learn full-stack web development using fastn in a week
Learn Now
ftd p1 grammar

ftd::p1 grammar

ftd is based on a low-level grammar called ftd::p1 grammar.

section

A ftd::p1 file is composed of "sections". A section looks like this:
an ftd::p1 file with two sections
-- section-kind section: the caption of the section
header-kind header-1: some header value
hello: world

the body of the first section

-- something:
yo: 42
Lang:
ftd

Each section starts with -- .

The section has these properties:

section kind

The section kind can be define after -- and before the section name. This is optional parameter.

In our case the section-kind is the section kind.

Since section kind is optional, so a section can be defined with or without section kind.
section with section kind
-- string name: Some caption

-- string list name:
Lang:
ftd
section without section kind
-- my-section:
Lang:
ftd

section name

The section name is the only mandatory parameter for a section. Name starts after -- or section kind if present, and ends with the first :. Trailing : is mandatory.

In our example, the name of the first section is some section, and the second section's name is something.

Section name contains alphanumeric characters, underscores, space, dots(.), hash(#), and hyphens(-). Colon terminates the section name.

Leading and trailing whitespaces are not considered part of the section name.

section caption

What comes after : in the section line, till the end of the first line is called the caption of the section.

The caption is optional.

In our example, the first section's caption is "the caption of the section", and the second section does not have a caption.

Leading and trailing whitespaces are not considered part of the caption.

section headers

After the "section line" (the first line that starts with -- ), zero or more section headers can be passed. Header can be passed in two ways: inline and block

A section header consists of name (mandantory), kind (optional) and value (optional).

inline header

In our example, the section has two headers, having names header-1 and hello, with values some header value and world respectively. Also the first header header-1 has kind header-kind

An empty newline or the start of a new section marks the end of the headers.

Leading and trailing whitespaces of both header name and header value are ignored.
inline header
-- section-kind section: the caption of the section
header-kind header-1: some header value
hello: world
Lang:
ftd

block header

We can also pass headers in block. This is commonly used when the value of header is long and passing it in inline creates readability issue.
block header
-- section-kind section-name:

-- section-name.block-header:

Lorem ipsum dolor sit amet. Vel magni dolorum et doloremque nostrum aut dicta unde 33 quod quisquam sed ducimus placeat et placeat reiciendis ad nostrum rerum. Qui quasi eserunt ut aliquid galisum et harum porro et libero facilis cum corporis voluptatem est beatae minima non voluptatem maxime. Est quod ipsum sed neque labore ut tempora porro ut quae distinctio ad enim voluptatem ex praesentium molestiae. Ea iusto consectetur ab sequi voluptatem et inventore iste.
Lang:
ftd

The block header can be declared after inline header. It starts with -- , follow by header kind, if present, then section name with . and after this header name. Now, header value can be passed in caption or body area.

In above example, the header name is block-header and has long value as Lorem ipsum dolor... which is passed as body

Header value can also take list of sections as value. And in that case, it needs end statement to show the closing of header.
block header
-- section-kind section-name:

-- section-name.block-header:

-- some section:

-- another section:

-- end: section-name.block-header
Lang:
ftd

section body

Like header, body can be passed in two ways: inline and block The body is optional.

Leading and trailing newlines are not considered part of the body.

inline body

After the first empty line that comes after the section header, till the start of next section is considered the body of the section.
Section with inline body
-- some section:

This is body


-- another section:
header: header value

This is body
Lang:
ftd

block body

A section body can be passed as a block. This is particularly helpful in case if the block headers are defined. In that case, the body can't be passed in inline.
Section with block body
-- some my-section:

.... some block headers

-- my-section.my-body:

This is body
Lang:
ftd

In above example, my-body is the body of section.

Unlike header, body doesn't accept list of sections as value.

sub-section

A section can contain zero or more sub-sections:
-- some-section:

-- subsection1: yo yo

-- subsection2:

subsection2 body

-- end: some-section
Lang:
ftd

subsections are nothing but list of sections itself. If subsections are defined, the section need to mark it's end using end keyword.

In above example, subsection1 and subsection2 are two subsections for some-section section. Also, the section is marked as end using -- end: some-section statement.

In above example, some-section section has two sub-sections, with names subsection1 and subsection2 respectively. The first one has a caption, yo yo, and the second one has a body, subsection2 body.

Programmatic Access

ftd::p11 module in ftd crate can be used to read ftd.p1 files. Wrappers of this crate in Python and other programming languages would hopefully come soon.
Copyright © 2023 - fastn.com