-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathadoc-server.js
More file actions
97 lines (82 loc) · 2.9 KB
/
Copy pathadoc-server.js
File metadata and controls
97 lines (82 loc) · 2.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import { URL } from "node:url";
import fs from "node:fs/promises";
import path from "node:path";
import http from "node:http";
import browserSync from "browser-sync";
import {
asciidocExtensions,
fileExists,
invokeInDir,
markdownExtensions,
normalizeSupportedExtnames,
} from "./utils.js";
import { adocConvert } from "./adoc-convert.js";
import { getTitleFromMarkdown, mdConvert } from "./md-convert.js";
export const createAsciidocMiddleware = (rootDir, config = {}) => {
const absoluteRootDir = path.resolve(rootDir);
return async (request, res, next) => {
try {
const url = new URL(request.url, "http://localhost");
// https://nodejs.org/en/knowledge/file-system/security/introduction/
if (url.pathname.includes("\0")) {
res.statusCode = 400;
return res.end(http.STATUS_CODES[res.statusCode]);
}
const extname = normalizeSupportedExtnames(path.extname(url.pathname));
if ([".md", ".adoc"].includes(extname)) {
const filePath = path.join(absoluteRootDir, url.pathname);
const exists = await fileExists(filePath);
if (!exists || !filePath.startsWith(absoluteRootDir)) {
res.statusCode = 404;
return res.end(http.STATUS_CODES[res.statusCode]);
}
const contents = await fs.readFile(filePath, { encoding: "utf8" });
let html = await invokeInDir(path.dirname(filePath), async () => {
switch (extname) {
case ".adoc": {
return adocConvert(contents, config.asciidoctorOptions);
}
case ".md": {
const title =
(await getTitleFromMarkdown(contents)) ?? "Untitled";
return mdConvert(contents, config.markdownOptions).then(
(body) =>
`<!DOCTYPE html><html><head><title>${title}</title></head><body>${body}</body></html>`
);
}
default: {
throw new Error(`Unsupported extension: ${extname}`);
}
}
});
res.setHeader("Content-Type", "text/html; charset=utf-8");
html = html.replace(
/<\/head>/,
`<script async src="//${request.headers.host}/browser-sync/browser-sync-client.js"></script></head>`
);
res.statusCode = 200;
return res.end(html);
}
} catch (error) {
return next(error);
}
next();
};
};
export const startAsciidocServer = async (rootDir = ".", config = {}) => {
const bs = browserSync.create();
bs.init({
files: `**/*.{${[...asciidocExtensions, ...markdownExtensions].join(",")}`,
server: rootDir,
injectFileTypes: [...asciidocExtensions, ...markdownExtensions],
middleware: [createAsciidocMiddleware(rootDir, config)],
directory: true,
open: false,
ui: false,
logSnippet: true,
watch: true,
injectChanges: false,
reloadOnRestart: true,
});
return bs;
};