-
Notifications
You must be signed in to change notification settings - Fork 1
/
pub.js
185 lines (162 loc) · 8.34 KB
/
pub.js
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
const fs = require("fs");
const path = require("path");
const glob = require("glob");
const { execSync } = require("child_process");
const YAML = require("yaml");
execSync("npx copyfiles -f pub/docusaurus.config.ts pub/build ", {stdio: "inherit"} )
execSync("npx copyfiles -f pub/sidebars.ts pub/build ", {stdio: "inherit"} )
execSync("npx copyfiles -f pub/img/* pub/build/static/img", {stdio: "inherit"} )
execSync("npx copy-folder wiki pub/build/docs", {stdio: "inherit"} )
// rename every README.md to the parent folder name, except for the root README.md. Rename that one to Table of Contents.md
// all links need to be updated to reflect the new file names. The links are typically relative, so we need to do something a bit advanced
// get all the README.md files
const readmeFiles = glob.sync("pub/build/docs/**/README.md").map(file => path.resolve(process.cwd(), file));
// get all wiki files
const wikiFiles = glob.sync("pub/build/docs/**/*.md");
// update the links in the wiki files first (and also add the header)
wikiFiles.forEach(file => {
let content = fs.readFileSync(file, "utf8");
let oldContent = content;
// get all instances of (?:../)*README.md
const matches = [...content.matchAll(/\(((?:[\w\.]*[\\\/])*)README\.md\)/g)];
// resolve the matches and check them against the README.md paths in the readmeFiles array
if (matches) {
matches.forEach(match => {
const dir = match[1] || "";
match = match[0];
// resolve the match to an absolute path
const resolved = path.resolve(process.cwd(), path.dirname(file), match.replace(/^\(/, "").replace(/\)$/, ""));
// check if the resolved path is in the readmeFiles array
if (readmeFiles.includes(resolved)) {
// if it is, update the content
// first replace the filename in the match
let newName = path.basename(path.dirname(resolved))
if( newName === "docs")
newName = "API"
newName = newName.replaceAll(" ", "%20")
const newMatch = match.replace(/^\(/, "").replace(/\)$/, "").replace("README", newName);
// then replace the match in the content
let safeMatch = `(?<![\\/])${ dir.replaceAll(/[\\\/]/g, "[\\/]").replaceAll(/\./g,"\\.") }README\\.md`;
safeMatchR = new RegExp(safeMatch, "g");
content = content.replaceAll(safeMatchR, newMatch);
}
});
}
let parent = path.basename(path.dirname(file))
const child = path.basename(file).replace(".md", "")
let title = child;
if( parent === "docs" ){
title = "API";
content = content
.replace(/## Documents/g, "## Additional Documents")
// [README](other/spec/spec.md) with [Overview](other/spec/spec.md)
.replace(/(?<=\[.*)[\\](?=.*\])/g, "/")
.replace(/## Modules/g, "## Other Modules Defined in This Library")
}
const isIndex = title.toUpperCase() === "README" || title.toUpperCase() === "INDEX"
if( isIndex ){
title = parent;
parent = path.basename(path.dirname(path.dirname(file)))
}
let sidebar_label = title === "API" ? "Table of Contents" : null;
let position;
// Rename titles as needed
switch( title ){
case "API":
sidebar_label = "Table of Contents";
content = content
.replace(/## Documents/g, "## Additional Documents")
// [README](other/spec/spec.md) with [Overview](other/spec/spec.md)
.replace(/(?<=\[.*)[\\](?=.*\])/g, "/")
//.replace(/\[spec\/README\]\(([^)]+)\)/g, "[spec/Overview]($1)")
.replace(/## Modules/g, "## Other Modules Defined in This Library")
// grab all non-empty lines between Documents and Modules
let match = oldContent.match(/## Documents([\s\S]*?)## Modules/);
let newMatch = content.match(/## Additional Documents([\s\S]*?)## Other Modules Defined in This Library/);
if( match ){
// split the match into lines
let lines = match[1].split("\n");
let newLines = newMatch[1].split("\n");
// split the link into the link text and the link
lines = lines.map(line => line.match(/\[(.*?)\]\((.*?)\)/));
newLines = newLines.map(line => line.match(/\[(.*?)\]\((.*?)\)/));
const links = lines.map(line => line ? {text: line[1], link: line[2]} : null).filter(Boolean);
const newLinks = newLines.map(line => line ? {text: line[1], link: line[2]} : null).filter(Boolean);
// resolve the links against `file`'s directory
links.forEach(link => {
link.resolved = path.resolve(path.dirname(file), link.link);
// check if newLinks contains a link with the same text
let newLink = newLinks.find(newLink => newLink.text === link.text.replace(/[\\\/]/g,"/"));
if( newLink ){
newLink.resolved = link.resolved;
}
});
// get the titles from the yaml frontmatter of the resolved links
newLinks.forEach(link => {
let childContent = fs.readFileSync(link.resolved, "utf8");
if( childContent ){
let header = childContent.match(/^---[\r\n]+([\s\S]*?)[\r\n]+---/);
if( header ){
let yaml = YAML.parse(header[1]);
if( yaml.pub_title || yaml.title ){
let path = link.text.split("/");
path.pop();
path.push(yaml.pub_title || yaml.title);
link.text = path.join("/");
}
}
}
});
const newDocumentsContent = newLinks.map(link => `- [${link.text}](${link.link})`).join("\n");
content = content.replace(/## Additional Documents([\s\S]*?)## Other Modules Defined in This Library/, `## Additional Documents\n\n${newDocumentsContent}\n\n## Other Modules Defined in This Library`);
}
break;
default: null;
}
// check if the file has a YAML header
let header = content.match(/^---[\r\n]+([\s\S]*?)[\r\n]+---/);
let yaml = {};
if( header ){
yaml = Object.assign({},YAML.parse(header[1]));
}
if( yaml.pub_title ){ // workaround for how typedoc handles anchor links
yaml.title = yaml.pub_title
} else if( !yaml.title && title )
yaml.title = title;
if( !yaml.sidebar_label && sidebar_label )
yaml.sidebar_label = sidebar_label;
if( !yaml.sidebar_position && position )
yaml.sidebar_position = position;
yaml.last_update = {
date: new Date().toLocaleDateString(),
author: "Automation"
}
header = `---\n${ YAML.stringify(yaml) }\n---\n`;
content = content.replace(/^---[\r\n]+([\s\S]*?)[\r\n]+---/, "");
content = `${header}${content}`;
// generate anchor links
// for each header line, add a docusaurus anchor link
content = content.replaceAll(/^(#+) ([^\{\}\r\n]+)$/gm, (match, level, header, offset, string, groups) => {
const anchor = header.toLowerCase().replace(/[\s]/g, "-").replace(/[^a-z0-9\-]/g, "");
return `${level} ${header} {#${anchor}}`;
})
// write the new content to the file
fs.writeFileSync(file, content);
});
// rename the README.md files
readmeFiles.forEach(file => {
let newPath;
if( path.basename(path.dirname(file)) === "docs") {
newPath = path.join(path.dirname(file), "API.md");
} else {
newPath = path.join(path.dirname(file), `${path.basename(path.dirname(file))}.md`);
}
console.log(`Renaming ${file} to ${newPath}`);
fs.renameSync(file, newPath);
})
execSync("npx copy-folder test/serve pub/build/static", {stdio: "inherit"} )
execSync("npx mkdirp pub/build/src/pages", {stdio: "inherit"} )
fs.renameSync("pub/build/static/index.html", "pub/build/static/playground.html")
execSync("npx copy-folder pub/src pub/build/src", {stdio: "inherit"} )
process.chdir("pub/build")
execSync("npx docusaurus build", {stdio: "inherit"} )