Repository navigation
Expand file tree
/
Copy pathcheck-tree.mjs
More file actions
94 lines (87 loc) · 3.38 KB
/
Copy pathcheck-tree.mjs
File metadata and controls
94 lines (87 loc) · 3.38 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
// What each output tree receives, derived from the build's own records.
//
// Split out of builder/check.mjs so the main thread can compute it
// during `dispatch` -- which is on the render fan-out's critical path --
// without pulling in link-check.mjs and, through it, htmlparser2's
// ~23 ms import. This module imports nothing but node:path, so a build
// without --check pays nothing for its presence.
//
// This is the piece that replaces check_links.mjs's directory walk, and
// the piece most able to fail silently. An entry missing here turns a
// working link into a reported break, which is loud. A spurious entry
// masks a real break, which is not. `tbdocs --check-audit-index` diffs
// the result against what actually landed on disk; see
// builder/check.mjs's auditIndex().
// Aux files the online tree receives after the pages are written. The symbol
// index is the online tree's alone: the IDE help add-in fetches it from the
// site, and the offline tree has no reader for it yet.
const ONLINE_AUX = [
"sitemap.xml",
"robots.txt",
"assets/js/search-data.json",
"assets/js/search-index.json",
"tB/symbols.json",
];
// The offline tree carries no sitemap, and the search index (with the search
// entries in it) not as JSON but as a script, search-index.js, since a page
// under file:// can load a script but not fetch a file; and the nav.js that
// puts the whole nav tree in place of a page's part of it.
const OFFLINE_AUX = ["assets/js/search-index.js", "assets/js/nav.js"];
// Every relative path a tree receives. `which` is "online" or "offline";
// the PDF tree's contents come from writePdf, which knows them exactly.
// `onlineOnlyRels` are files the online tree receives and the offline one
// does not: the help add-in's project file.
export function deriveTreeRels(
which,
{ pages, staticFiles, stubs, themeAssetRels, excludePatterns, onlineOnlyRels = [] },
) {
const rels = new Set();
const add =
which === "offline"
? (rel) => {
const r = posix(rel);
if (!excluded(r, excludePatterns)) rels.add(r);
}
: (rel) => rels.add(posix(rel));
for (const p of pages) {
if (p.frontmatter?.layout === "book-combined") continue;
add(p.destPath);
}
for (const s of stubs) add(s.destPath);
for (const s of staticFiles) add(s.destRel);
for (const rel of themeAssetRels) add(rel);
for (const rel of which === "offline" ? OFFLINE_AUX : ONLINE_AUX) add(rel);
if (which !== "offline") for (const rel of onlineOnlyRels) add(rel);
return [...rels];
}
export function posix(p) {
return String(p).replaceAll("\\", "/");
}
// offlineExcluded's rule, inlined rather than imported: offline-rewrite.mjs
// is a much larger module and this is two functions.
function excluded(rel, patterns) {
if (!patterns || !patterns.length) return false;
return patterns.some((pat) => (/[*?]/.test(pat) ? fnmatch(pat, rel) : pat === rel));
}
// File.fnmatch(..., FNM_PATHNAME): `*` does not cross `/`, `**` does.
function fnmatch(pattern, str) {
let re = "^";
for (let i = 0; i < pattern.length; i++) {
const c = pattern[i];
if (c === "*") {
if (pattern[i + 1] === "*") {
re += ".*";
i++;
} else {
re += "[^/]*";
}
} else if (c === "?") {
re += "[^/]";
} else if (".+^$()|[]{}\\".includes(c)) {
re += "\\" + c;
} else {
re += c;
}
}
return new RegExp(re + "$").test(str);
}