@webpieces/docs-site 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -0
- package/package.json +28 -0
- package/src/DocsSiteError.d.ts +24 -0
- package/src/DocsSiteError.js +33 -0
- package/src/DocsSiteError.js.map +1 -0
- package/src/assets/SiteScript.d.ts +11 -0
- package/src/assets/SiteScript.js +88 -0
- package/src/assets/SiteScript.js.map +1 -0
- package/src/assets/SiteStyles.d.ts +13 -0
- package/src/assets/SiteStyles.js +106 -0
- package/src/assets/SiteStyles.js.map +1 -0
- package/src/cli/DocsSiteCli.d.ts +37 -0
- package/src/cli/DocsSiteCli.js +116 -0
- package/src/cli/DocsSiteCli.js.map +1 -0
- package/src/cli/WpDocsSiteMain.d.ts +21 -0
- package/src/cli/WpDocsSiteMain.js +60 -0
- package/src/cli/WpDocsSiteMain.js.map +1 -0
- package/src/cli/wp-docs-site.d.ts +2 -0
- package/src/cli/wp-docs-site.js +22 -0
- package/src/cli/wp-docs-site.js.map +1 -0
- package/src/emit/SiteWriter.d.ts +13 -0
- package/src/emit/SiteWriter.js +34 -0
- package/src/emit/SiteWriter.js.map +1 -0
- package/src/index.d.ts +41 -0
- package/src/index.js +105 -0
- package/src/index.js.map +1 -0
- package/src/manifest/DocsManifest.d.ts +28 -0
- package/src/manifest/DocsManifest.js +44 -0
- package/src/manifest/DocsManifest.js.map +1 -0
- package/src/manifest/ProseLoader.d.ts +23 -0
- package/src/manifest/ProseLoader.js +81 -0
- package/src/manifest/ProseLoader.js.map +1 -0
- package/src/markdown/Markdown.d.ts +47 -0
- package/src/markdown/Markdown.js +178 -0
- package/src/markdown/Markdown.js.map +1 -0
- package/src/render/CardRenderer.d.ts +28 -0
- package/src/render/CardRenderer.js +70 -0
- package/src/render/CardRenderer.js.map +1 -0
- package/src/render/FieldTreeRenderer.d.ts +34 -0
- package/src/render/FieldTreeRenderer.js +91 -0
- package/src/render/FieldTreeRenderer.js.map +1 -0
- package/src/render/Html.d.ts +14 -0
- package/src/render/Html.js +28 -0
- package/src/render/Html.js.map +1 -0
- package/src/render/Layout.d.ts +21 -0
- package/src/render/Layout.js +74 -0
- package/src/render/Layout.js.map +1 -0
- package/src/render/NavModel.d.ts +47 -0
- package/src/render/NavModel.js +86 -0
- package/src/render/NavModel.js.map +1 -0
- package/src/render/OperationPageRenderer.d.ts +44 -0
- package/src/render/OperationPageRenderer.js +102 -0
- package/src/render/OperationPageRenderer.js.map +1 -0
- package/src/render/SitePage.d.ts +30 -0
- package/src/render/SitePage.js +46 -0
- package/src/render/SitePage.js.map +1 -0
- package/src/render/SiteRenderer.d.ts +34 -0
- package/src/render/SiteRenderer.js +121 -0
- package/src/render/SiteRenderer.js.map +1 -0
- package/src/render/SiteUrls.d.ts +24 -0
- package/src/render/SiteUrls.js +37 -0
- package/src/render/SiteUrls.js.map +1 -0
- package/src/samples/CodeSamples.d.ts +49 -0
- package/src/samples/CodeSamples.js +166 -0
- package/src/samples/CodeSamples.js.map +1 -0
- package/src/serve/DevServer.d.ts +35 -0
- package/src/serve/DevServer.js +109 -0
- package/src/serve/DevServer.js.map +1 -0
- package/src/spec/ApiSpec.d.ts +110 -0
- package/src/spec/ApiSpec.js +165 -0
- package/src/spec/ApiSpec.js.map +1 -0
- package/src/spec/ExampleBuilder.d.ts +32 -0
- package/src/spec/ExampleBuilder.js +119 -0
- package/src/spec/ExampleBuilder.js.map +1 -0
- package/src/spec/FieldTree.d.ts +75 -0
- package/src/spec/FieldTree.js +155 -0
- package/src/spec/FieldTree.js.map +1 -0
- package/src/spec/JsonNode.d.ts +53 -0
- package/src/spec/JsonNode.js +93 -0
- package/src/spec/JsonNode.js.map +1 -0
- package/src/spec/SchemaLens.d.ts +57 -0
- package/src/spec/SchemaLens.js +162 -0
- package/src/spec/SchemaLens.js.map +1 -0
- package/src/spec/SchemaShape.d.ts +22 -0
- package/src/spec/SchemaShape.js +61 -0
- package/src/spec/SchemaShape.js.map +1 -0
- package/src/spec/Slug.d.ts +16 -0
- package/src/spec/Slug.js +43 -0
- package/src/spec/Slug.js.map +1 -0
- package/src/spec/SpecLoader.d.ts +26 -0
- package/src/spec/SpecLoader.js +64 -0
- package/src/spec/SpecLoader.js.map +1 -0
- package/src/spec/SpecReader.d.ts +46 -0
- package/src/spec/SpecReader.js +174 -0
- package/src/spec/SpecReader.js.map +1 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Markdown = void 0;
|
|
4
|
+
const Html_1 = require("../render/Html");
|
|
5
|
+
/**
|
|
6
|
+
* A DOCUMENTED SUBSET of CommonMark, over trusted, PR-reviewed input — the JSDoc a developer wrote
|
|
7
|
+
* and the markdown files a manifest names. It is not a CommonMark implementation and does not try to
|
|
8
|
+
* be; #985 puts a full one explicitly out of scope, because the alternative to ~180 lines here is a
|
|
9
|
+
* dependency in every upstream project that wants an API reference.
|
|
10
|
+
*
|
|
11
|
+
* What it renders:
|
|
12
|
+
*
|
|
13
|
+
* | block | spelling |
|
|
14
|
+
* |---|---|
|
|
15
|
+
* | heading | `#` through `######` |
|
|
16
|
+
* | fenced code | ` ``` ` with an optional language word |
|
|
17
|
+
* | table | a `\|` row, then a `\|---\|` row, then rows |
|
|
18
|
+
* | list | `- ` / `* ` for bullets, `1. ` for numbers |
|
|
19
|
+
* | blockquote | `> ` |
|
|
20
|
+
* | rule | `---` on its own line |
|
|
21
|
+
* | paragraph | anything else, blank-line separated |
|
|
22
|
+
*
|
|
23
|
+
* and inline: `` `code` ``, `**bold**`, `*italic*`, `[text](url)`.
|
|
24
|
+
*
|
|
25
|
+
* **Everything is HTML-escaped first**, before any inline pattern runs, so a `<` in a JSDoc body is
|
|
26
|
+
* text rather than the start of a tag. That ordering is the whole safety argument: escape-then-mark
|
|
27
|
+
* cannot produce a tag the source did not ask for, while mark-then-escape would escape the tags this
|
|
28
|
+
* renderer just wrote.
|
|
29
|
+
*/
|
|
30
|
+
class Markdown {
|
|
31
|
+
html = new Html_1.Html();
|
|
32
|
+
/** The rendered HTML for a markdown document. */
|
|
33
|
+
render(source) {
|
|
34
|
+
const lines = source.replace(/\r\n/g, '\n').split('\n');
|
|
35
|
+
const out = [];
|
|
36
|
+
let index = 0;
|
|
37
|
+
while (index < lines.length) {
|
|
38
|
+
const consumed = this.block(lines, index, out);
|
|
39
|
+
index = consumed > index ? consumed : index + 1;
|
|
40
|
+
}
|
|
41
|
+
return out.join('\n');
|
|
42
|
+
}
|
|
43
|
+
/** Inline markdown only — for a place that is already one line, like a table cell. */
|
|
44
|
+
inline(source) {
|
|
45
|
+
const escaped = this.html.escape(source);
|
|
46
|
+
return escaped
|
|
47
|
+
.replace(/`([^`]+)`/g, '<code>$1</code>')
|
|
48
|
+
.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g, '<a href="$2">$1</a>')
|
|
49
|
+
.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
|
|
50
|
+
.replace(/(^|[^*])\*([^*]+)\*/g, '$1<em>$2</em>');
|
|
51
|
+
}
|
|
52
|
+
/** @returns the index of the first line AFTER the block this consumed. */
|
|
53
|
+
block(lines, start, out) {
|
|
54
|
+
const line = lines[start] ?? '';
|
|
55
|
+
if (line.trim() === '') {
|
|
56
|
+
return start + 1;
|
|
57
|
+
}
|
|
58
|
+
if (line.startsWith('```')) {
|
|
59
|
+
return this.fence(lines, start, out);
|
|
60
|
+
}
|
|
61
|
+
if (/^#{1,6}\s/.test(line)) {
|
|
62
|
+
return this.heading(line, start, out);
|
|
63
|
+
}
|
|
64
|
+
if (/^(-{3,}|\*{3,})\s*$/.test(line.trim())) {
|
|
65
|
+
out.push('<hr />');
|
|
66
|
+
return start + 1;
|
|
67
|
+
}
|
|
68
|
+
if (line.trimStart().startsWith('|') && this.isDivider(lines[start + 1])) {
|
|
69
|
+
return this.table(lines, start, out);
|
|
70
|
+
}
|
|
71
|
+
if (this.isBullet(line) || this.isNumber(line)) {
|
|
72
|
+
return this.list(lines, start, out);
|
|
73
|
+
}
|
|
74
|
+
if (line.trimStart().startsWith('> ')) {
|
|
75
|
+
return this.quote(lines, start, out);
|
|
76
|
+
}
|
|
77
|
+
return this.paragraph(lines, start, out);
|
|
78
|
+
}
|
|
79
|
+
fence(lines, start, out) {
|
|
80
|
+
const language = (lines[start] ?? '').slice(3).trim();
|
|
81
|
+
const body = [];
|
|
82
|
+
let index = start + 1;
|
|
83
|
+
while (index < lines.length && !(lines[index] ?? '').startsWith('```')) {
|
|
84
|
+
body.push(lines[index] ?? '');
|
|
85
|
+
index++;
|
|
86
|
+
}
|
|
87
|
+
const languageClass = language === '' ? '' : ` class="language-${this.html.escape(language)}"`;
|
|
88
|
+
out.push(`<pre><code${languageClass}>${this.html.escape(body.join('\n'))}</code></pre>`);
|
|
89
|
+
return index + 1;
|
|
90
|
+
}
|
|
91
|
+
heading(line, start, out) {
|
|
92
|
+
const hashes = (/^#{1,6}/.exec(line) ?? [''])[0].length;
|
|
93
|
+
out.push(`<h${hashes}>${this.inline(line.slice(hashes).trim())}</h${hashes}>`);
|
|
94
|
+
return start + 1;
|
|
95
|
+
}
|
|
96
|
+
table(lines, start, out) {
|
|
97
|
+
const header = this.cells(lines[start] ?? '');
|
|
98
|
+
const rows = [];
|
|
99
|
+
let index = start + 2;
|
|
100
|
+
while (index < lines.length && (lines[index] ?? '').trimStart().startsWith('|')) {
|
|
101
|
+
rows.push(this.cells(lines[index] ?? ''));
|
|
102
|
+
index++;
|
|
103
|
+
}
|
|
104
|
+
const head = header.map((cell) => `<th>${this.inline(cell)}</th>`).join('');
|
|
105
|
+
const body = rows
|
|
106
|
+
.map((row) => `<tr>${row.map((cell) => `<td>${this.inline(cell)}</td>`).join('')}</tr>`)
|
|
107
|
+
.join('');
|
|
108
|
+
out.push(`<table><thead><tr>${head}</tr></thead><tbody>${body}</tbody></table>`);
|
|
109
|
+
return index;
|
|
110
|
+
}
|
|
111
|
+
list(lines, start, out) {
|
|
112
|
+
const ordered = this.isNumber(lines[start] ?? '');
|
|
113
|
+
const items = [];
|
|
114
|
+
let index = start;
|
|
115
|
+
while (index < lines.length &&
|
|
116
|
+
(this.isBullet(lines[index] ?? '') || this.isNumber(lines[index] ?? ''))) {
|
|
117
|
+
items.push(this.inline(this.itemTextOf(lines[index] ?? '')));
|
|
118
|
+
index++;
|
|
119
|
+
}
|
|
120
|
+
const tag = ordered ? 'ol' : 'ul';
|
|
121
|
+
const body = items.map((item) => `<li>${item}</li>`).join('');
|
|
122
|
+
out.push(`<${tag}>${body}</${tag}>`);
|
|
123
|
+
return index;
|
|
124
|
+
}
|
|
125
|
+
quote(lines, start, out) {
|
|
126
|
+
const body = [];
|
|
127
|
+
let index = start;
|
|
128
|
+
while (index < lines.length && (lines[index] ?? '').trimStart().startsWith('> ')) {
|
|
129
|
+
body.push((lines[index] ?? '').trimStart().slice(2));
|
|
130
|
+
index++;
|
|
131
|
+
}
|
|
132
|
+
out.push(`<blockquote>${this.render(body.join('\n'))}</blockquote>`);
|
|
133
|
+
return index;
|
|
134
|
+
}
|
|
135
|
+
paragraph(lines, start, out) {
|
|
136
|
+
const body = [];
|
|
137
|
+
let index = start;
|
|
138
|
+
while (index < lines.length &&
|
|
139
|
+
(lines[index] ?? '').trim() !== '' &&
|
|
140
|
+
!this.startsBlock(lines, index)) {
|
|
141
|
+
body.push(lines[index] ?? '');
|
|
142
|
+
index++;
|
|
143
|
+
}
|
|
144
|
+
out.push(`<p>${this.inline(body.join('\n'))}</p>`);
|
|
145
|
+
return index === start ? start + 1 : index;
|
|
146
|
+
}
|
|
147
|
+
/** True when the line at `index` begins a block that a paragraph must not swallow. */
|
|
148
|
+
startsBlock(lines, index) {
|
|
149
|
+
if (index === 0) {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
const line = lines[index] ?? '';
|
|
153
|
+
return (line.startsWith('```') ||
|
|
154
|
+
/^#{1,6}\s/.test(line) ||
|
|
155
|
+
this.isBullet(line) ||
|
|
156
|
+
this.isNumber(line) ||
|
|
157
|
+
line.trimStart().startsWith('> ') ||
|
|
158
|
+
(line.trimStart().startsWith('|') && this.isDivider(lines[index + 1])));
|
|
159
|
+
}
|
|
160
|
+
isDivider(line) {
|
|
161
|
+
return line !== undefined && /^\s*\|[\s:|-]+\|\s*$/.test(line);
|
|
162
|
+
}
|
|
163
|
+
isBullet(line) {
|
|
164
|
+
return /^\s*[-*]\s+/.test(line);
|
|
165
|
+
}
|
|
166
|
+
isNumber(line) {
|
|
167
|
+
return /^\s*\d+\.\s+/.test(line);
|
|
168
|
+
}
|
|
169
|
+
itemTextOf(line) {
|
|
170
|
+
return line.replace(/^\s*(?:[-*]|\d+\.)\s+/, '');
|
|
171
|
+
}
|
|
172
|
+
cells(line) {
|
|
173
|
+
const trimmed = line.trim().replace(/^\|/, '').replace(/\|$/, '');
|
|
174
|
+
return trimmed.split('|').map((cell) => cell.trim());
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
exports.Markdown = Markdown;
|
|
178
|
+
//# sourceMappingURL=Markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Markdown.js","sourceRoot":"","sources":["../../../../../../packages/docs/docs-site/src/markdown/Markdown.ts"],"names":[],"mappings":"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","sourcesContent":["import { Html } from '../render/Html';\n\n/**\n * A DOCUMENTED SUBSET of CommonMark, over trusted, PR-reviewed input — the JSDoc a developer wrote\n * and the markdown files a manifest names. It is not a CommonMark implementation and does not try to\n * be; #985 puts a full one explicitly out of scope, because the alternative to ~180 lines here is a\n * dependency in every upstream project that wants an API reference.\n *\n * What it renders:\n *\n * | block | spelling |\n * |---|---|\n * | heading | `#` through `######` |\n * | fenced code | ` ``` ` with an optional language word |\n * | table | a `\\|` row, then a `\\|---\\|` row, then rows |\n * | list | `- ` / `* ` for bullets, `1. ` for numbers |\n * | blockquote | `> ` |\n * | rule | `---` on its own line |\n * | paragraph | anything else, blank-line separated |\n *\n * and inline: `` `code` ``, `**bold**`, `*italic*`, `[text](url)`.\n *\n * **Everything is HTML-escaped first**, before any inline pattern runs, so a `<` in a JSDoc body is\n * text rather than the start of a tag. That ordering is the whole safety argument: escape-then-mark\n * cannot produce a tag the source did not ask for, while mark-then-escape would escape the tags this\n * renderer just wrote.\n */\nexport class Markdown {\n private readonly html = new Html();\n\n /** The rendered HTML for a markdown document. */\n render(source: string): string {\n const lines = source.replace(/\\r\\n/g, '\\n').split('\\n');\n const out: string[] = [];\n let index = 0;\n while (index < lines.length) {\n const consumed = this.block(lines, index, out);\n index = consumed > index ? consumed : index + 1;\n }\n return out.join('\\n');\n }\n\n /** Inline markdown only — for a place that is already one line, like a table cell. */\n inline(source: string): string {\n const escaped = this.html.escape(source);\n return escaped\n .replace(/`([^`]+)`/g, '<code>$1</code>')\n .replace(/\\[([^\\]]+)\\]\\(([^)\\s]+)\\)/g, '<a href=\"$2\">$1</a>')\n .replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>')\n .replace(/(^|[^*])\\*([^*]+)\\*/g, '$1<em>$2</em>');\n }\n\n /** @returns the index of the first line AFTER the block this consumed. */\n private block(lines: readonly string[], start: number, out: string[]): number {\n const line = lines[start] ?? '';\n if (line.trim() === '') {\n return start + 1;\n }\n if (line.startsWith('```')) {\n return this.fence(lines, start, out);\n }\n if (/^#{1,6}\\s/.test(line)) {\n return this.heading(line, start, out);\n }\n if (/^(-{3,}|\\*{3,})\\s*$/.test(line.trim())) {\n out.push('<hr />');\n return start + 1;\n }\n if (line.trimStart().startsWith('|') && this.isDivider(lines[start + 1])) {\n return this.table(lines, start, out);\n }\n if (this.isBullet(line) || this.isNumber(line)) {\n return this.list(lines, start, out);\n }\n if (line.trimStart().startsWith('> ')) {\n return this.quote(lines, start, out);\n }\n return this.paragraph(lines, start, out);\n }\n\n private fence(lines: readonly string[], start: number, out: string[]): number {\n const language = (lines[start] ?? '').slice(3).trim();\n const body: string[] = [];\n let index = start + 1;\n while (index < lines.length && !(lines[index] ?? '').startsWith('```')) {\n body.push(lines[index] ?? '');\n index++;\n }\n const languageClass =\n language === '' ? '' : ` class=\"language-${this.html.escape(language)}\"`;\n out.push(`<pre><code${languageClass}>${this.html.escape(body.join('\\n'))}</code></pre>`);\n return index + 1;\n }\n\n private heading(line: string, start: number, out: string[]): number {\n const hashes = (/^#{1,6}/.exec(line) ?? [''])[0].length;\n out.push(`<h${hashes}>${this.inline(line.slice(hashes).trim())}</h${hashes}>`);\n return start + 1;\n }\n\n private table(lines: readonly string[], start: number, out: string[]): number {\n const header = this.cells(lines[start] ?? '');\n const rows: string[][] = [];\n let index = start + 2;\n while (index < lines.length && (lines[index] ?? '').trimStart().startsWith('|')) {\n rows.push(this.cells(lines[index] ?? ''));\n index++;\n }\n const head = header.map((cell: string): string => `<th>${this.inline(cell)}</th>`).join('');\n const body = rows\n .map(\n (row: string[]): string =>\n `<tr>${row.map((cell: string): string => `<td>${this.inline(cell)}</td>`).join('')}</tr>`,\n )\n .join('');\n out.push(`<table><thead><tr>${head}</tr></thead><tbody>${body}</tbody></table>`);\n return index;\n }\n\n private list(lines: readonly string[], start: number, out: string[]): number {\n const ordered = this.isNumber(lines[start] ?? '');\n const items: string[] = [];\n let index = start;\n while (\n index < lines.length &&\n (this.isBullet(lines[index] ?? '') || this.isNumber(lines[index] ?? ''))\n ) {\n items.push(this.inline(this.itemTextOf(lines[index] ?? '')));\n index++;\n }\n const tag = ordered ? 'ol' : 'ul';\n const body = items.map((item: string): string => `<li>${item}</li>`).join('');\n out.push(`<${tag}>${body}</${tag}>`);\n return index;\n }\n\n private quote(lines: readonly string[], start: number, out: string[]): number {\n const body: string[] = [];\n let index = start;\n while (index < lines.length && (lines[index] ?? '').trimStart().startsWith('> ')) {\n body.push((lines[index] ?? '').trimStart().slice(2));\n index++;\n }\n out.push(`<blockquote>${this.render(body.join('\\n'))}</blockquote>`);\n return index;\n }\n\n private paragraph(lines: readonly string[], start: number, out: string[]): number {\n const body: string[] = [];\n let index = start;\n while (\n index < lines.length &&\n (lines[index] ?? '').trim() !== '' &&\n !this.startsBlock(lines, index)\n ) {\n body.push(lines[index] ?? '');\n index++;\n }\n out.push(`<p>${this.inline(body.join('\\n'))}</p>`);\n return index === start ? start + 1 : index;\n }\n\n /** True when the line at `index` begins a block that a paragraph must not swallow. */\n private startsBlock(lines: readonly string[], index: number): boolean {\n if (index === 0) {\n return false;\n }\n const line = lines[index] ?? '';\n return (\n line.startsWith('```') ||\n /^#{1,6}\\s/.test(line) ||\n this.isBullet(line) ||\n this.isNumber(line) ||\n line.trimStart().startsWith('> ') ||\n (line.trimStart().startsWith('|') && this.isDivider(lines[index + 1]))\n );\n }\n\n private isDivider(line: string | undefined): boolean {\n return line !== undefined && /^\\s*\\|[\\s:|-]+\\|\\s*$/.test(line);\n }\n\n private isBullet(line: string): boolean {\n return /^\\s*[-*]\\s+/.test(line);\n }\n\n private isNumber(line: string): boolean {\n return /^\\s*\\d+\\.\\s+/.test(line);\n }\n\n private itemTextOf(line: string): string {\n return line.replace(/^\\s*(?:[-*]|\\d+\\.)\\s+/, '');\n }\n\n private cells(line: string): string[] {\n const trimmed = line.trim().replace(/^\\|/, '').replace(/\\|$/, '');\n return trimmed.split('|').map((cell: string): string => cell.trim());\n }\n}\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { CodeSample } from '../samples/CodeSamples';
|
|
2
|
+
import { OperationInfo, SecuritySchemeInfo } from '../spec/ApiSpec';
|
|
3
|
+
/** The card heading above the code samples, and the control beside it. */
|
|
4
|
+
export declare const REQUEST_LABEL = "REQUEST";
|
|
5
|
+
export declare const COLLAPSE_ALL_LABEL = "COLLAPSE ALL";
|
|
6
|
+
/**
|
|
7
|
+
* The sticky card column: what to authenticate with, and how to call it.
|
|
8
|
+
*
|
|
9
|
+
* `COLLAPSE ALL` lives here rather than in the body because it acts on the WHOLE body — a control
|
|
10
|
+
* that collapses everything belongs beside the thing that stays put while the body scrolls.
|
|
11
|
+
*/
|
|
12
|
+
export declare class CardRenderer {
|
|
13
|
+
private readonly html;
|
|
14
|
+
/**
|
|
15
|
+
* The authorization card: the credentials THIS operation requires, named by the header they are
|
|
16
|
+
* sent in. Absent when the operation requires none — an empty card saying "no authorization"
|
|
17
|
+
* reads, at a glance, exactly like a card whose contents failed to render.
|
|
18
|
+
*/
|
|
19
|
+
authorization(operation: OperationInfo, schemes: readonly SecuritySchemeInfo[]): string;
|
|
20
|
+
/** The code samples, one tab per language, the first one visible with JS off. */
|
|
21
|
+
samples(samples: readonly CodeSample[]): string;
|
|
22
|
+
/** A card holding one JSON example — the response body, or a schema page's sample. */
|
|
23
|
+
example(title: string, json: string): string;
|
|
24
|
+
/** A plain card: a title and markup this package already rendered. */
|
|
25
|
+
panel(title: string, body: string): string;
|
|
26
|
+
private schemeRow;
|
|
27
|
+
private card;
|
|
28
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CardRenderer = exports.COLLAPSE_ALL_LABEL = exports.REQUEST_LABEL = void 0;
|
|
4
|
+
const Html_1 = require("./Html");
|
|
5
|
+
/** The card heading above the code samples, and the control beside it. */
|
|
6
|
+
exports.REQUEST_LABEL = 'REQUEST';
|
|
7
|
+
exports.COLLAPSE_ALL_LABEL = 'COLLAPSE ALL';
|
|
8
|
+
/**
|
|
9
|
+
* The sticky card column: what to authenticate with, and how to call it.
|
|
10
|
+
*
|
|
11
|
+
* `COLLAPSE ALL` lives here rather than in the body because it acts on the WHOLE body — a control
|
|
12
|
+
* that collapses everything belongs beside the thing that stays put while the body scrolls.
|
|
13
|
+
*/
|
|
14
|
+
class CardRenderer {
|
|
15
|
+
html = new Html_1.Html();
|
|
16
|
+
/**
|
|
17
|
+
* The authorization card: the credentials THIS operation requires, named by the header they are
|
|
18
|
+
* sent in. Absent when the operation requires none — an empty card saying "no authorization"
|
|
19
|
+
* reads, at a glance, exactly like a card whose contents failed to render.
|
|
20
|
+
*/
|
|
21
|
+
authorization(operation, schemes) {
|
|
22
|
+
const required = schemes.filter((scheme) => operation.securityKeys.includes(scheme.key));
|
|
23
|
+
if (required.length === 0) {
|
|
24
|
+
return '';
|
|
25
|
+
}
|
|
26
|
+
const rows = required
|
|
27
|
+
.map((scheme) => this.schemeRow(scheme))
|
|
28
|
+
.join('');
|
|
29
|
+
return this.card('AUTHORIZATION', '', `<div>${rows}</div>`);
|
|
30
|
+
}
|
|
31
|
+
/** The code samples, one tab per language, the first one visible with JS off. */
|
|
32
|
+
samples(samples) {
|
|
33
|
+
if (samples.length === 0) {
|
|
34
|
+
return '';
|
|
35
|
+
}
|
|
36
|
+
const tabs = samples
|
|
37
|
+
.map((sample, index) => `<button class="tab" type="button" data-language="${this.html.escape(sample.id)}" aria-selected="${index === 0 ? 'true' : 'false'}">${this.html.escape(sample.label)}</button>`)
|
|
38
|
+
.join('');
|
|
39
|
+
const blocks = samples
|
|
40
|
+
.map((sample, index) => `<pre class="sample" data-language="${this.html.escape(sample.id)}"${index === 0 ? '' : ' hidden'}><code>${this.html.escape(sample.source)}</code></pre>`)
|
|
41
|
+
.join('');
|
|
42
|
+
return this.card(exports.REQUEST_LABEL, `<button class="collapse-all" type="button">${exports.COLLAPSE_ALL_LABEL}</button>`, `<div class="tabs">${tabs}</div><div class="card-body">${blocks}</div>`, false);
|
|
43
|
+
}
|
|
44
|
+
/** A card holding one JSON example — the response body, or a schema page's sample. */
|
|
45
|
+
example(title, json) {
|
|
46
|
+
if (json === '') {
|
|
47
|
+
return '';
|
|
48
|
+
}
|
|
49
|
+
return this.card(title, '', `<pre><code>${this.html.escape(json)}</code></pre>`);
|
|
50
|
+
}
|
|
51
|
+
/** A plain card: a title and markup this package already rendered. */
|
|
52
|
+
panel(title, body) {
|
|
53
|
+
return this.card(title, '', body);
|
|
54
|
+
}
|
|
55
|
+
schemeRow(scheme) {
|
|
56
|
+
const where = scheme.headerName === ''
|
|
57
|
+
? this.html.escape(scheme.kind)
|
|
58
|
+
: `<code>${this.html.escape(scheme.headerName)}</code>`;
|
|
59
|
+
const prose = scheme.description === undefined
|
|
60
|
+
? ''
|
|
61
|
+
: `<div class="field-doc">${this.html.escape(scheme.description)}</div>`;
|
|
62
|
+
return `<div class="field"><div class="field-head"><span class="field-name">${this.html.escape(scheme.key)}</span><span class="field-type">${where}</span></div>${prose}</div>`;
|
|
63
|
+
}
|
|
64
|
+
card(title, control, body, wrapBody = true) {
|
|
65
|
+
const inner = wrapBody ? `<div class="card-body">${body}</div>` : body;
|
|
66
|
+
return `<section class="card"><div class="card-head"><span>${this.html.escape(title)}</span>${control}</div>${inner}</section>`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.CardRenderer = CardRenderer;
|
|
70
|
+
//# sourceMappingURL=CardRenderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CardRenderer.js","sourceRoot":"","sources":["../../../../../../packages/docs/docs-site/src/render/CardRenderer.ts"],"names":[],"mappings":"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","sourcesContent":["import { CodeSample } from '../samples/CodeSamples';\nimport { Html } from './Html';\nimport { OperationInfo, SecuritySchemeInfo } from '../spec/ApiSpec';\n\n/** The card heading above the code samples, and the control beside it. */\nexport const REQUEST_LABEL = 'REQUEST';\nexport const COLLAPSE_ALL_LABEL = 'COLLAPSE ALL';\n\n/**\n * The sticky card column: what to authenticate with, and how to call it.\n *\n * `COLLAPSE ALL` lives here rather than in the body because it acts on the WHOLE body — a control\n * that collapses everything belongs beside the thing that stays put while the body scrolls.\n */\nexport class CardRenderer {\n private readonly html = new Html();\n\n /**\n * The authorization card: the credentials THIS operation requires, named by the header they are\n * sent in. Absent when the operation requires none — an empty card saying \"no authorization\"\n * reads, at a glance, exactly like a card whose contents failed to render.\n */\n authorization(operation: OperationInfo, schemes: readonly SecuritySchemeInfo[]): string {\n const required = schemes.filter((scheme: SecuritySchemeInfo): boolean =>\n operation.securityKeys.includes(scheme.key),\n );\n if (required.length === 0) {\n return '';\n }\n const rows = required\n .map((scheme: SecuritySchemeInfo): string => this.schemeRow(scheme))\n .join('');\n return this.card('AUTHORIZATION', '', `<div>${rows}</div>`);\n }\n\n /** The code samples, one tab per language, the first one visible with JS off. */\n samples(samples: readonly CodeSample[]): string {\n if (samples.length === 0) {\n return '';\n }\n const tabs = samples\n .map(\n (sample: CodeSample, index: number): string =>\n `<button class=\"tab\" type=\"button\" data-language=\"${this.html.escape(sample.id)}\" aria-selected=\"${index === 0 ? 'true' : 'false'}\">${this.html.escape(sample.label)}</button>`,\n )\n .join('');\n const blocks = samples\n .map(\n (sample: CodeSample, index: number): string =>\n `<pre class=\"sample\" data-language=\"${this.html.escape(sample.id)}\"${index === 0 ? '' : ' hidden'}><code>${this.html.escape(sample.source)}</code></pre>`,\n )\n .join('');\n return this.card(\n REQUEST_LABEL,\n `<button class=\"collapse-all\" type=\"button\">${COLLAPSE_ALL_LABEL}</button>`,\n `<div class=\"tabs\">${tabs}</div><div class=\"card-body\">${blocks}</div>`,\n false,\n );\n }\n\n /** A card holding one JSON example — the response body, or a schema page's sample. */\n example(title: string, json: string): string {\n if (json === '') {\n return '';\n }\n return this.card(title, '', `<pre><code>${this.html.escape(json)}</code></pre>`);\n }\n\n /** A plain card: a title and markup this package already rendered. */\n panel(title: string, body: string): string {\n return this.card(title, '', body);\n }\n\n private schemeRow(scheme: SecuritySchemeInfo): string {\n const where =\n scheme.headerName === ''\n ? this.html.escape(scheme.kind)\n : `<code>${this.html.escape(scheme.headerName)}</code>`;\n const prose =\n scheme.description === undefined\n ? ''\n : `<div class=\"field-doc\">${this.html.escape(scheme.description)}</div>`;\n return `<div class=\"field\"><div class=\"field-head\"><span class=\"field-name\">${this.html.escape(scheme.key)}</span><span class=\"field-type\">${where}</span></div>${prose}</div>`;\n }\n\n private card(title: string, control: string, body: string, wrapBody = true): string {\n const inner = wrapBody ? `<div class=\"card-body\">${body}</div>` : body;\n return `<section class=\"card\"><div class=\"card-head\"><span>${this.html.escape(title)}</span>${control}</div>${inner}</section>`;\n }\n}\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { FieldNode, SchemaVariant } from '../spec/FieldTree';
|
|
2
|
+
import { Markdown } from '../markdown/Markdown';
|
|
3
|
+
import { SiteUrls } from './SiteUrls';
|
|
4
|
+
/** The literal line a reader Ctrl-Fs for when they want to know what an enum accepts. */
|
|
5
|
+
export declare const POSSIBLE_VALUES = "Possible values:";
|
|
6
|
+
/**
|
|
7
|
+
* Renders the parameter tree: field name, type label, prose, and — for an enum — the COMPLETE
|
|
8
|
+
* `Possible values:` chip line.
|
|
9
|
+
*
|
|
10
|
+
* The list is complete or it is absent; there is no "…and 3 more". A truncated list of accepted
|
|
11
|
+
* values is the shape of documentation that makes a partner guess, and the guess is a 400 they
|
|
12
|
+
* cannot debug from the page they are reading.
|
|
13
|
+
*
|
|
14
|
+
* A field whose type is a named object renders as a LINK to that object's page and is NOT expanded
|
|
15
|
+
* underneath — see `FieldTreeBuilder` for why the example body resolves the same reference fully.
|
|
16
|
+
*/
|
|
17
|
+
export declare class FieldTreeRenderer {
|
|
18
|
+
private readonly markdown;
|
|
19
|
+
private readonly urls;
|
|
20
|
+
private readonly html;
|
|
21
|
+
constructor(markdown: Markdown, urls: SiteUrls);
|
|
22
|
+
/** One tree. `prefix` is the page's `../` prefix, so the links work at any hosting path. */
|
|
23
|
+
render(fields: readonly FieldNode[], prefix: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* The `oneOf` variants, ALL EXPANDED, one labelled block per branch keyed by its discriminator
|
|
26
|
+
* value. Never tabbed: a partner writing one handler needs every shape at once, and a tab is
|
|
27
|
+
* invisible to Ctrl-F and to print.
|
|
28
|
+
*/
|
|
29
|
+
renderVariants(variants: readonly SchemaVariant[], discriminator: string, prefix: string): string;
|
|
30
|
+
private variant;
|
|
31
|
+
private field;
|
|
32
|
+
private typeLabel;
|
|
33
|
+
private chips;
|
|
34
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FieldTreeRenderer = exports.POSSIBLE_VALUES = void 0;
|
|
4
|
+
const Html_1 = require("./Html");
|
|
5
|
+
/** The literal line a reader Ctrl-Fs for when they want to know what an enum accepts. */
|
|
6
|
+
exports.POSSIBLE_VALUES = 'Possible values:';
|
|
7
|
+
/**
|
|
8
|
+
* Renders the parameter tree: field name, type label, prose, and — for an enum — the COMPLETE
|
|
9
|
+
* `Possible values:` chip line.
|
|
10
|
+
*
|
|
11
|
+
* The list is complete or it is absent; there is no "…and 3 more". A truncated list of accepted
|
|
12
|
+
* values is the shape of documentation that makes a partner guess, and the guess is a 400 they
|
|
13
|
+
* cannot debug from the page they are reading.
|
|
14
|
+
*
|
|
15
|
+
* A field whose type is a named object renders as a LINK to that object's page and is NOT expanded
|
|
16
|
+
* underneath — see `FieldTreeBuilder` for why the example body resolves the same reference fully.
|
|
17
|
+
*/
|
|
18
|
+
class FieldTreeRenderer {
|
|
19
|
+
markdown;
|
|
20
|
+
urls;
|
|
21
|
+
html = new Html_1.Html();
|
|
22
|
+
constructor(markdown, urls) {
|
|
23
|
+
this.markdown = markdown;
|
|
24
|
+
this.urls = urls;
|
|
25
|
+
}
|
|
26
|
+
/** One tree. `prefix` is the page's `../` prefix, so the links work at any hosting path. */
|
|
27
|
+
render(fields, prefix) {
|
|
28
|
+
if (fields.length === 0) {
|
|
29
|
+
return '<p class="field-doc">No fields.</p>';
|
|
30
|
+
}
|
|
31
|
+
return fields.map((field) => this.field(field, prefix)).join('');
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The `oneOf` variants, ALL EXPANDED, one labelled block per branch keyed by its discriminator
|
|
35
|
+
* value. Never tabbed: a partner writing one handler needs every shape at once, and a tab is
|
|
36
|
+
* invisible to Ctrl-F and to print.
|
|
37
|
+
*/
|
|
38
|
+
renderVariants(variants, discriminator, prefix) {
|
|
39
|
+
return variants
|
|
40
|
+
.map((variant) => this.variant(variant, discriminator, prefix))
|
|
41
|
+
.join('');
|
|
42
|
+
}
|
|
43
|
+
variant(variant, discriminator, prefix) {
|
|
44
|
+
const key = variant.discriminatorValue === '' || discriminator === ''
|
|
45
|
+
? ''
|
|
46
|
+
: ` — <code>${this.html.escape(discriminator)}: "${this.html.escape(variant.discriminatorValue)}"</code>`;
|
|
47
|
+
return [
|
|
48
|
+
'<section class="variant">',
|
|
49
|
+
`<div class="variant-head">${this.html.escape(variant.label)}${key}</div>`,
|
|
50
|
+
this.render(variant.fields, prefix),
|
|
51
|
+
'</section>',
|
|
52
|
+
].join('');
|
|
53
|
+
}
|
|
54
|
+
field(field, prefix) {
|
|
55
|
+
const parts = ['<div class="field">', '<div class="field-head">'];
|
|
56
|
+
parts.push(`<span class="field-name">${this.html.escape(field.name)}</span>`);
|
|
57
|
+
parts.push(`<span class="field-type">${this.typeLabel(field, prefix)}</span>`);
|
|
58
|
+
if (field.required) {
|
|
59
|
+
parts.push('<span class="field-required">REQUIRED</span>');
|
|
60
|
+
}
|
|
61
|
+
parts.push('</div>');
|
|
62
|
+
if (field.description !== '') {
|
|
63
|
+
parts.push(`<div class="field-doc">${this.markdown.render(field.description)}</div>`);
|
|
64
|
+
}
|
|
65
|
+
parts.push(this.chips(field));
|
|
66
|
+
if (field.children.length > 0) {
|
|
67
|
+
parts.push(`<div class="field-children">${this.render(field.children, prefix)}</div>`);
|
|
68
|
+
}
|
|
69
|
+
parts.push('</div>');
|
|
70
|
+
return parts.join('');
|
|
71
|
+
}
|
|
72
|
+
typeLabel(field, prefix) {
|
|
73
|
+
if (field.linkTo === undefined) {
|
|
74
|
+
return this.html.escape(field.typeLabel);
|
|
75
|
+
}
|
|
76
|
+
const href = `${prefix}${this.urls.schema(field.linkTo)}`;
|
|
77
|
+
const label = this.html.escape(field.typeLabel);
|
|
78
|
+
return `<a href="${href}">${label}</a>`;
|
|
79
|
+
}
|
|
80
|
+
chips(field) {
|
|
81
|
+
if (field.possibleValues.length === 0) {
|
|
82
|
+
return '';
|
|
83
|
+
}
|
|
84
|
+
const chips = field.possibleValues
|
|
85
|
+
.map((value) => `<span class="chip">${this.html.escape(value)}</span>`)
|
|
86
|
+
.join('');
|
|
87
|
+
return `<div class="chips">${exports.POSSIBLE_VALUES} ${chips}</div>`;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.FieldTreeRenderer = FieldTreeRenderer;
|
|
91
|
+
//# sourceMappingURL=FieldTreeRenderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FieldTreeRenderer.js","sourceRoot":"","sources":["../../../../../../packages/docs/docs-site/src/render/FieldTreeRenderer.ts"],"names":[],"mappings":"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","sourcesContent":["import { FieldNode, SchemaVariant } from '../spec/FieldTree';\nimport { Html } from './Html';\nimport { Markdown } from '../markdown/Markdown';\nimport { SiteUrls } from './SiteUrls';\n\n/** The literal line a reader Ctrl-Fs for when they want to know what an enum accepts. */\nexport const POSSIBLE_VALUES = 'Possible values:';\n\n/**\n * Renders the parameter tree: field name, type label, prose, and — for an enum — the COMPLETE\n * `Possible values:` chip line.\n *\n * The list is complete or it is absent; there is no \"…and 3 more\". A truncated list of accepted\n * values is the shape of documentation that makes a partner guess, and the guess is a 400 they\n * cannot debug from the page they are reading.\n *\n * A field whose type is a named object renders as a LINK to that object's page and is NOT expanded\n * underneath — see `FieldTreeBuilder` for why the example body resolves the same reference fully.\n */\nexport class FieldTreeRenderer {\n private readonly html = new Html();\n\n constructor(\n private readonly markdown: Markdown,\n private readonly urls: SiteUrls,\n ) {}\n\n /** One tree. `prefix` is the page's `../` prefix, so the links work at any hosting path. */\n render(fields: readonly FieldNode[], prefix: string): string {\n if (fields.length === 0) {\n return '<p class=\"field-doc\">No fields.</p>';\n }\n return fields.map((field: FieldNode): string => this.field(field, prefix)).join('');\n }\n\n /**\n * The `oneOf` variants, ALL EXPANDED, one labelled block per branch keyed by its discriminator\n * value. Never tabbed: a partner writing one handler needs every shape at once, and a tab is\n * invisible to Ctrl-F and to print.\n */\n renderVariants(\n variants: readonly SchemaVariant[],\n discriminator: string,\n prefix: string,\n ): string {\n return variants\n .map((variant: SchemaVariant): string => this.variant(variant, discriminator, prefix))\n .join('');\n }\n\n private variant(variant: SchemaVariant, discriminator: string, prefix: string): string {\n const key =\n variant.discriminatorValue === '' || discriminator === ''\n ? ''\n : ` — <code>${this.html.escape(discriminator)}: \"${this.html.escape(variant.discriminatorValue)}\"</code>`;\n return [\n '<section class=\"variant\">',\n `<div class=\"variant-head\">${this.html.escape(variant.label)}${key}</div>`,\n this.render(variant.fields, prefix),\n '</section>',\n ].join('');\n }\n\n private field(field: FieldNode, prefix: string): string {\n const parts = ['<div class=\"field\">', '<div class=\"field-head\">'];\n parts.push(`<span class=\"field-name\">${this.html.escape(field.name)}</span>`);\n parts.push(`<span class=\"field-type\">${this.typeLabel(field, prefix)}</span>`);\n if (field.required) {\n parts.push('<span class=\"field-required\">REQUIRED</span>');\n }\n parts.push('</div>');\n if (field.description !== '') {\n parts.push(`<div class=\"field-doc\">${this.markdown.render(field.description)}</div>`);\n }\n parts.push(this.chips(field));\n if (field.children.length > 0) {\n parts.push(`<div class=\"field-children\">${this.render(field.children, prefix)}</div>`);\n }\n parts.push('</div>');\n return parts.join('');\n }\n\n private typeLabel(field: FieldNode, prefix: string): string {\n if (field.linkTo === undefined) {\n return this.html.escape(field.typeLabel);\n }\n const href = `${prefix}${this.urls.schema(field.linkTo)}`;\n const label = this.html.escape(field.typeLabel);\n return `<a href=\"${href}\">${label}</a>`;\n }\n\n private chips(field: FieldNode): string {\n if (field.possibleValues.length === 0) {\n return '';\n }\n const chips = field.possibleValues\n .map((value: string): string => `<span class=\"chip\">${this.html.escape(value)}</span>`)\n .join('');\n return `<div class=\"chips\">${POSSIBLE_VALUES} ${chips}</div>`;\n }\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML escaping, in ONE place.
|
|
3
|
+
*
|
|
4
|
+
* Every string that reaches the page comes from a document or a markdown file this run read, and
|
|
5
|
+
* both are text. So there is exactly one rule and no exceptions to remember: a value is escaped on
|
|
6
|
+
* its way into the page, and the only thing that is not escaped is markup this package itself wrote.
|
|
7
|
+
* Two escaping helpers would be two rules, and the second one is where an unescaped `<` gets in.
|
|
8
|
+
*/
|
|
9
|
+
export declare class Html {
|
|
10
|
+
/** Text into an element body or a double-quoted attribute. */
|
|
11
|
+
escape(text: string): string;
|
|
12
|
+
/** One `<a>` to an in-site page. `href` is written by this package, never by a document. */
|
|
13
|
+
link(href: string, text: string): string;
|
|
14
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Html = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* HTML escaping, in ONE place.
|
|
6
|
+
*
|
|
7
|
+
* Every string that reaches the page comes from a document or a markdown file this run read, and
|
|
8
|
+
* both are text. So there is exactly one rule and no exceptions to remember: a value is escaped on
|
|
9
|
+
* its way into the page, and the only thing that is not escaped is markup this package itself wrote.
|
|
10
|
+
* Two escaping helpers would be two rules, and the second one is where an unescaped `<` gets in.
|
|
11
|
+
*/
|
|
12
|
+
class Html {
|
|
13
|
+
/** Text into an element body or a double-quoted attribute. */
|
|
14
|
+
escape(text) {
|
|
15
|
+
return text
|
|
16
|
+
.replace(/&/g, '&')
|
|
17
|
+
.replace(/</g, '<')
|
|
18
|
+
.replace(/>/g, '>')
|
|
19
|
+
.replace(/"/g, '"')
|
|
20
|
+
.replace(/'/g, ''');
|
|
21
|
+
}
|
|
22
|
+
/** One `<a>` to an in-site page. `href` is written by this package, never by a document. */
|
|
23
|
+
link(href, text) {
|
|
24
|
+
return `<a href="${href}">${this.escape(text)}</a>`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.Html = Html;
|
|
28
|
+
//# sourceMappingURL=Html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Html.js","sourceRoot":"","sources":["../../../../../../packages/docs/docs-site/src/render/Html.ts"],"names":[],"mappings":";;;AAAA;;;;;;;GAOG;AACH,MAAa,IAAI;IACb,8DAA8D;IAC9D,MAAM,CAAC,IAAY;QACf,OAAO,IAAI;aACN,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;aACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;aACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;aACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;aACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC;IAED,4FAA4F;IAC5F,IAAI,CAAC,IAAY,EAAE,IAAY;QAC3B,OAAO,YAAY,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;IACxD,CAAC;CACJ;AAfD,oBAeC","sourcesContent":["/**\n * HTML escaping, in ONE place.\n *\n * Every string that reaches the page comes from a document or a markdown file this run read, and\n * both are text. So there is exactly one rule and no exceptions to remember: a value is escaped on\n * its way into the page, and the only thing that is not escaped is markup this package itself wrote.\n * Two escaping helpers would be two rules, and the second one is where an unescaped `<` gets in.\n */\nexport class Html {\n /** Text into an element body or a double-quoted attribute. */\n escape(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n }\n\n /** One `<a>` to an in-site page. `href` is written by this package, never by a document. */\n link(href: string, text: string): string {\n return `<a href=\"${href}\">${this.escape(text)}</a>`;\n }\n}\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { NavModel } from './NavModel';
|
|
2
|
+
import { SiteUrls } from './SiteUrls';
|
|
3
|
+
/**
|
|
4
|
+
* The three-pane shell every page shares: the collapsible nav tree, the operation body, and the
|
|
5
|
+
* sticky card column.
|
|
6
|
+
*
|
|
7
|
+
* Every link is RELATIVE and ends in `index.html`; {@link SiteUrls} carries that reasoning.
|
|
8
|
+
*/
|
|
9
|
+
export declare class Layout {
|
|
10
|
+
private readonly nav;
|
|
11
|
+
private readonly urls;
|
|
12
|
+
private readonly siteTitle;
|
|
13
|
+
private readonly siteVersion;
|
|
14
|
+
private readonly html;
|
|
15
|
+
constructor(nav: NavModel, urls: SiteUrls, siteTitle: string, siteVersion: string);
|
|
16
|
+
/** One complete HTML document. `body` and `cards` are markup this package already rendered. */
|
|
17
|
+
render(url: string, pageTitle: string, body: string, cards: string): string;
|
|
18
|
+
private navPane;
|
|
19
|
+
private navGroup;
|
|
20
|
+
private navLink;
|
|
21
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Layout = void 0;
|
|
4
|
+
const Html_1 = require("./Html");
|
|
5
|
+
/**
|
|
6
|
+
* The three-pane shell every page shares: the collapsible nav tree, the operation body, and the
|
|
7
|
+
* sticky card column.
|
|
8
|
+
*
|
|
9
|
+
* Every link is RELATIVE and ends in `index.html`; {@link SiteUrls} carries that reasoning.
|
|
10
|
+
*/
|
|
11
|
+
class Layout {
|
|
12
|
+
nav;
|
|
13
|
+
urls;
|
|
14
|
+
siteTitle;
|
|
15
|
+
siteVersion;
|
|
16
|
+
html = new Html_1.Html();
|
|
17
|
+
constructor(nav, urls, siteTitle, siteVersion) {
|
|
18
|
+
this.nav = nav;
|
|
19
|
+
this.urls = urls;
|
|
20
|
+
this.siteTitle = siteTitle;
|
|
21
|
+
this.siteVersion = siteVersion;
|
|
22
|
+
}
|
|
23
|
+
/** One complete HTML document. `body` and `cards` are markup this package already rendered. */
|
|
24
|
+
render(url, pageTitle, body, cards) {
|
|
25
|
+
const prefix = this.urls.prefixFor(url);
|
|
26
|
+
return [
|
|
27
|
+
'<!doctype html>',
|
|
28
|
+
'<html lang="en">',
|
|
29
|
+
'<head>',
|
|
30
|
+
'<meta charset="utf-8" />',
|
|
31
|
+
'<meta name="viewport" content="width=device-width, initial-scale=1" />',
|
|
32
|
+
`<title>${this.html.escape(pageTitle)} · ${this.html.escape(this.siteTitle)}</title>`,
|
|
33
|
+
`<link rel="stylesheet" href="${prefix}styles.css" />`,
|
|
34
|
+
'</head>',
|
|
35
|
+
'<body>',
|
|
36
|
+
'<div class="site">',
|
|
37
|
+
this.navPane(prefix, url),
|
|
38
|
+
`<main class="pane-body">${body}</main>`,
|
|
39
|
+
`<aside class="pane-cards"><div class="pane-cards-inner">${cards}</div></aside>`,
|
|
40
|
+
'</div>',
|
|
41
|
+
`<script src="${prefix}site.js"></script>`,
|
|
42
|
+
'</body>',
|
|
43
|
+
'</html>',
|
|
44
|
+
'',
|
|
45
|
+
].join('\n');
|
|
46
|
+
}
|
|
47
|
+
navPane(prefix, current) {
|
|
48
|
+
const parts = [
|
|
49
|
+
'<nav class="pane-nav">',
|
|
50
|
+
`<a class="site-title" href="${prefix}${this.urls.home()}">${this.html.escape(this.siteTitle)}</a>`,
|
|
51
|
+
`<div class="site-version">${this.html.escape(this.siteVersion)}</div>`,
|
|
52
|
+
'<button class="theme-toggle" type="button">Theme</button>',
|
|
53
|
+
];
|
|
54
|
+
for (const group of this.nav.groups) {
|
|
55
|
+
parts.push(this.navGroup(group, prefix, current));
|
|
56
|
+
}
|
|
57
|
+
parts.push('</nav>');
|
|
58
|
+
return parts.join('\n');
|
|
59
|
+
}
|
|
60
|
+
navGroup(group, prefix, current) {
|
|
61
|
+
const open = group.links.some((link) => link.url === current);
|
|
62
|
+
const items = group.links
|
|
63
|
+
.map((link) => this.navLink(link, prefix, current))
|
|
64
|
+
.join('');
|
|
65
|
+
return `<details class="nav-group"${open ? ' open' : ''}><summary>${this.html.escape(group.title)}</summary><ul>${items}</ul></details>`;
|
|
66
|
+
}
|
|
67
|
+
navLink(link, prefix, current) {
|
|
68
|
+
const badge = link.badge === '' ? '' : `<span class="badge">${this.html.escape(link.badge)}</span>`;
|
|
69
|
+
const marker = link.url === current ? ' class="current"' : '';
|
|
70
|
+
return `<li><a href="${prefix}${link.url}"${marker}>${badge}<span>${this.html.escape(link.title)}</span></a></li>`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.Layout = Layout;
|
|
74
|
+
//# sourceMappingURL=Layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Layout.js","sourceRoot":"","sources":["../../../../../../packages/docs/docs-site/src/render/Layout.ts"],"names":[],"mappings":"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","sourcesContent":["import { Html } from './Html';\nimport { NavGroup, NavLink, NavModel } from './NavModel';\nimport { SiteUrls } from './SiteUrls';\n\n/**\n * The three-pane shell every page shares: the collapsible nav tree, the operation body, and the\n * sticky card column.\n *\n * Every link is RELATIVE and ends in `index.html`; {@link SiteUrls} carries that reasoning.\n */\nexport class Layout {\n private readonly html = new Html();\n\n constructor(\n private readonly nav: NavModel,\n private readonly urls: SiteUrls,\n private readonly siteTitle: string,\n private readonly siteVersion: string,\n ) {}\n\n /** One complete HTML document. `body` and `cards` are markup this package already rendered. */\n render(url: string, pageTitle: string, body: string, cards: string): string {\n const prefix = this.urls.prefixFor(url);\n return [\n '<!doctype html>',\n '<html lang=\"en\">',\n '<head>',\n '<meta charset=\"utf-8\" />',\n '<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />',\n `<title>${this.html.escape(pageTitle)} · ${this.html.escape(this.siteTitle)}</title>`,\n `<link rel=\"stylesheet\" href=\"${prefix}styles.css\" />`,\n '</head>',\n '<body>',\n '<div class=\"site\">',\n this.navPane(prefix, url),\n `<main class=\"pane-body\">${body}</main>`,\n `<aside class=\"pane-cards\"><div class=\"pane-cards-inner\">${cards}</div></aside>`,\n '</div>',\n `<script src=\"${prefix}site.js\"></script>`,\n '</body>',\n '</html>',\n '',\n ].join('\\n');\n }\n\n private navPane(prefix: string, current: string): string {\n const parts = [\n '<nav class=\"pane-nav\">',\n `<a class=\"site-title\" href=\"${prefix}${this.urls.home()}\">${this.html.escape(this.siteTitle)}</a>`,\n `<div class=\"site-version\">${this.html.escape(this.siteVersion)}</div>`,\n '<button class=\"theme-toggle\" type=\"button\">Theme</button>',\n ];\n for (const group of this.nav.groups) {\n parts.push(this.navGroup(group, prefix, current));\n }\n parts.push('</nav>');\n return parts.join('\\n');\n }\n\n private navGroup(group: NavGroup, prefix: string, current: string): string {\n const open = group.links.some((link: NavLink): boolean => link.url === current);\n const items = group.links\n .map((link: NavLink): string => this.navLink(link, prefix, current))\n .join('');\n return `<details class=\"nav-group\"${open ? ' open' : ''}><summary>${this.html.escape(group.title)}</summary><ul>${items}</ul></details>`;\n }\n\n private navLink(link: NavLink, prefix: string, current: string): string {\n const badge =\n link.badge === '' ? '' : `<span class=\"badge\">${this.html.escape(link.badge)}</span>`;\n const marker = link.url === current ? ' class=\"current\"' : '';\n return `<li><a href=\"${prefix}${link.url}\"${marker}>${badge}<span>${this.html.escape(link.title)}</span></a></li>`;\n }\n}\n"]}
|