Skip to content

Commit 4082284

Browse files
committed
[Docs] Generate stdlib docs with Jsonnet.
Benefits: * Keeping things consistent should be easier. * We can now change the way it is represented in HTML without going over the whole thing. * We can now use the stdlib data programatically, so it should be easier to check it's in line with reality. * Make it easier to integrate with any potential documentation generation tools. * First step towards completely Jsonnet-based site generation which I think is worth exploring.
1 parent d75e953 commit 4082284

File tree

9 files changed

+2193
-441
lines changed

9 files changed

+2193
-441
lines changed

Diff for: README.md

+7
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,10 @@ tools/scripts/serve_docs.sh
148148

149149
This should the website on localhost:8200, automatically rebuild when you change any underlying
150150
files, and automatically refresh your browser when that happens.
151+
152+
The standard library is documented in a structured format in `doc/_stdlib_gen/stdlib-content.jsonnet`.
153+
The HTML (input for Jekyll) is regenerated using the following command:
154+
155+
```
156+
tools/scripts/update_web_content.sh
157+
```

Diff for: doc/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
production
2+
.jekyll-cache/

Diff for: doc/_config.yml

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
destination: production
22
markdown: redcarpet
33
highlighter: pygments
4+
exclude: ['_stdlib_gen']

Diff for: doc/_stdlib_gen/html.libsonnet

+167
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
// A little helper library for building HTML documents with Jsonnet.
2+
//
3+
// Parts of the HTML document (elements, comments, etc.) are represented
4+
// as Jsonnet objects and arrays.
5+
//
6+
// The following types are available:
7+
// * element – HTML element
8+
// * comment – HTML comment
9+
// * doctype – HTML doctype (e.g. <!DOCTYPE html>)
10+
// * verbatim – verbatim HTML code,
11+
// * array – HTML parts seprated by whitespace
12+
// * spaceless – HTML parts concatenated without any separator.
13+
//
14+
// The library predefines functions for common elements, but
15+
// it is easy to define your own.
16+
//
17+
// The library takes a somewhat opinionated approach to HTML formatting.
18+
// It is possible to get a specific formatting with `verbatim` and `spaceless`
19+
// types, but normally the `render` function automatically handles indentations
20+
// and newlines. The outputs are intended to be diff friendly and readable.
21+
22+
local element(elementType, bodyFormatting='indented') = function(attrs, body) {
23+
type: 'element',
24+
elementType: elementType,
25+
attrs: attrs,
26+
body: body,
27+
bodyFormatting: bodyFormatting,
28+
};
29+
local comment(text) = {
30+
type: 'comment',
31+
text: text,
32+
};
33+
local doctype(doctype) = {
34+
type: 'doctype',
35+
doctype: doctype,
36+
};
37+
local verbatim(html) = {
38+
type: 'verbatim',
39+
html: html,
40+
};
41+
local spaceless(parts) = {
42+
type: 'spaceless',
43+
parts: parts,
44+
};
45+
46+
local renderAttrs(attrs) =
47+
std.join(' ', [
48+
attr + '="' + attrs[attr] + '"'
49+
for attr in std.objectFields(attrs)
50+
]);
51+
52+
local renderOpeningTag(type, attrs) =
53+
local attrsStr = renderAttrs(attrs);
54+
'<' +
55+
type +
56+
(
57+
if attrsStr != '' then
58+
' ' + attrsStr
59+
else
60+
''
61+
)
62+
+
63+
'>';
64+
65+
local renderClosingTag(type) =
66+
'</' +
67+
type +
68+
'>';
69+
70+
71+
local paragraphs(ps) = [element('p')({}, p) for p in ps];
72+
local newline = verbatim('\n');
73+
74+
local indentString(s, indent) =
75+
local lines = std.split(s, '\n');
76+
// If the string ends with a newline, drop it.
77+
local lines2 =
78+
if lines[std.length(lines) - 1] == '' then
79+
lines[:std.length(lines) - 1]
80+
else
81+
lines
82+
;
83+
std.join('\n' + indent, lines2)
84+
;
85+
86+
local
87+
render(content) = renderAux(content, indent=' ', curIndent=''),
88+
renderAux(content, indent, curIndent) =
89+
local renderIndented(c) =
90+
'\n' +
91+
curIndent +
92+
indent +
93+
renderAux(c, indent, curIndent + indent) +
94+
'\n' +
95+
curIndent
96+
;
97+
if std.isObject(content) then
98+
if content.type == 'element' then
99+
renderOpeningTag(content.elementType, content.attrs) +
100+
(
101+
if content.bodyFormatting == 'indented' then
102+
renderIndented(content.body)
103+
else if content.bodyFormatting == 'compact' then
104+
renderAux(content.body, indent, curIndent)
105+
else if content.bodyFormatting == 'unindented' then
106+
renderAux(content.body, indent, '')
107+
else
108+
error ("Invalid bodyFormatting: " + content.bodyFormatting)
109+
) +
110+
renderClosingTag(content.elementType)
111+
else if content.type == 'comment' then
112+
'<!-- ' + content.text + ' -->'
113+
else if content.type == 'doctype' then
114+
'<!DOCTYPE ' + content.doctype + ' />'
115+
else if content.type == 'verbatim' then
116+
content.html
117+
else if content.type == 'spaceless' then
118+
std.join('', [renderAux(c, indent, curIndent) for c in content.parts if c != null])
119+
else error 'unrecognized type'
120+
else if std.isArray(content) then
121+
std.join('\n' + curIndent, [renderAux(c, indent, curIndent) for c in content if c != null])
122+
else if std.isString(content) then
123+
indentString(content, curIndent)
124+
else
125+
'content must be an object, an array or a string';
126+
127+
// Escape HTML characters (e.g. for including HTML in pre)
128+
// TODO(sbarzowski) consider adding a variant which also removes quotation marks (like html.escape in Python)
129+
local escape(str) =
130+
std.strReplace(
131+
std.strReplace(
132+
std.strReplace(str, "&", "&amp;"),
133+
"<", "&lt;"),
134+
">", "&gt;");
135+
136+
{
137+
// Basics:
138+
element: element,
139+
doctype: doctype,
140+
comment: comment,
141+
verbatim: verbatim,
142+
spaceless: spaceless,
143+
render: render,
144+
escape: escape,
145+
146+
// Elements:
147+
a: element('a'),
148+
body: element('body'),
149+
html: element('html'),
150+
head: element('head'),
151+
h1: element('h1'),
152+
h2: element('h2'),
153+
h3: element('h3'),
154+
h4: element('h4'),
155+
h5: element('h5'),
156+
h6: element('h6'),
157+
p: element('p'),
158+
div: element('div'),
159+
code: element('code', bodyFormatting='compact'),
160+
pre: element('pre', bodyFormatting='unindented'),
161+
em: element('em'),
162+
svg: element('svg'),
163+
164+
// Batteries:
165+
paragraphs: paragraphs,
166+
newline: newline,
167+
}

Diff for: doc/_stdlib_gen/jekyll.libsonnet

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
local html = import 'html.libsonnet';
2+
3+
local renderWithFrontMatter(params, body) =
4+
'---\n' +
5+
'# AUTOGENERATED FILE. DO NOT EDIT BY HAND!\n' +
6+
std.join('\n', [
7+
std.toString(p) + ': ' + std.toString(params[p])
8+
for p in std.objectFields(params)
9+
]) +
10+
'\n---\n\n' +
11+
html.render(body)
12+
;
13+
14+
{
15+
renderWithFrontMatter: renderWithFrontMatter,
16+
}

0 commit comments

Comments
 (0)