Skip to content

Commit a0e83e1

Browse files
committed
added docs builder
1 parent 1c37a82 commit a0e83e1

File tree

2 files changed

+169
-1
lines changed

2 files changed

+169
-1
lines changed

build-docs..js

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
//get all *.md files in ./docs, reccursively, and store them in an array, with their properties in the first block, they're from obsidian
2+
const fs = require('fs');
3+
const path = require('path');
4+
5+
function parseFrontMatter(content) {
6+
const lines = content.trim().split('\n');
7+
let metadata = {};
8+
let contentStart = 0;
9+
10+
if (lines[0].trim() === '---') {
11+
let endMetadata = lines.findIndex((line, index) => index > 0 && line.trim() === '---');
12+
if (endMetadata !== -1) {
13+
metadata = Object.fromEntries(
14+
lines.slice(1, endMetadata)
15+
.map(line => line.match(/^([\w-]+):\s*(.*)$/))
16+
.filter(Boolean)
17+
.map(([, key, value]) => [key, value.trim()])
18+
);
19+
contentStart = endMetadata + 1;
20+
}
21+
}
22+
23+
return {
24+
metadata,
25+
content: lines.slice(contentStart).join('\n').trim()
26+
};
27+
}
28+
29+
function sanitizeTitle(str) {
30+
return str
31+
.toLowerCase()
32+
.replace(/[^\w\s-]/g, '')
33+
.replace(/\s+/g, '-');
34+
}
35+
36+
function parseFolderDoc(folder, folderName) {
37+
const folderDocPath = path.join(folder, folderName + '.md');
38+
let folderMetadata = {};
39+
let folderPathRel = null;
40+
41+
if (fs.existsSync(folderDocPath)) {
42+
const folderDocContent = fs.readFileSync(folderDocPath, 'utf-8');
43+
const { metadata } = parseFrontMatter(folderDocContent);
44+
if (!metadata.slug) {
45+
metadata.slug = metadata.title
46+
? sanitizeTitle(metadata.title)
47+
: sanitizeTitle(folderName);
48+
}
49+
folderPathRel = path.relative(__dirname, folderDocPath).replace(/\\/g, '/');
50+
folderMetadata = { ...metadata };
51+
}
52+
return { folderPathRel, folderMetadata };
53+
}
54+
55+
function parseMdFile(fullPath) {
56+
const content = fs.readFileSync(fullPath, 'utf-8');
57+
const { metadata } = parseFrontMatter(content);
58+
if (!metadata.slug) {
59+
metadata.slug = metadata.title
60+
? sanitizeTitle(metadata.title)
61+
: sanitizeTitle(path.parse(fullPath).name);
62+
}
63+
let result = {
64+
...metadata,
65+
title: metadata.title || path.parse(fullPath).name,
66+
slug: metadata.slug
67+
};
68+
69+
const parsedPath = path.relative(__dirname, fullPath).replace(/\\/g, '/');
70+
if (parsedPath) {
71+
result.path = parsedPath;
72+
}
73+
74+
return result;
75+
}
76+
77+
function processFolder(folder, parentSlug = '') {
78+
const folderName = path.parse(folder).name;
79+
const { folderPathRel, folderMetadata } = parseFolderDoc(folder, folderName);
80+
81+
let folderSlug = folderMetadata.slug || sanitizeTitle(folderName);
82+
if (folderName.toLowerCase() === 'docs' && !parentSlug) {
83+
folderSlug = '';
84+
} else if (parentSlug) {
85+
folderSlug = parentSlug + '/' + folderSlug;
86+
}
87+
88+
const items = [];
89+
fs.readdirSync(folder).forEach(item => {
90+
const fullPath = path.join(folder, item);
91+
const stat = fs.statSync(fullPath);
92+
if (stat.isDirectory() && !item.startsWith('.') && item !== 'images') {
93+
items.push(processFolder(fullPath, folderSlug));
94+
} else if (path.extname(item) === '.md' &&
95+
fullPath !== folderPathRel?.replace(/\//g, path.sep) &&
96+
path.parse(item).name.toLowerCase() !== folderName.toLowerCase()) {
97+
const file = parseMdFile(fullPath);
98+
file.slug = folderSlug ? `${folderSlug}/${file.slug}` : file.slug;
99+
items.push(file);
100+
}
101+
});
102+
103+
let result = {
104+
...folderMetadata,
105+
title: folderMetadata.title || folderName,
106+
type: 'folder',
107+
slug: folderSlug,
108+
items
109+
};
110+
111+
if (folderPathRel) {
112+
result.path = folderPathRel;
113+
}
114+
115+
return result;
116+
}
117+
118+
function readAllMarkdownFiles(dir) {
119+
const root = processFolder(dir);
120+
return root.items;
121+
}
122+
123+
function loadIndexTemplate() {
124+
const indexPath = path.join(__dirname, 'index.json');
125+
try {
126+
const indexData = JSON.parse(fs.readFileSync(indexPath, 'utf-8'));
127+
// Strip out documents array, keeping all other properties
128+
delete indexData.documents;
129+
return indexData;
130+
} catch (error) {
131+
console.error('Error reading index.json:', error);
132+
return {
133+
defaultPage: "welcome",
134+
metadata: {
135+
title: "Documentation",
136+
description: "Documentation",
137+
thumbnail: "img/og-image.png",
138+
site_name: "Documentation"
139+
},
140+
author: {}
141+
};
142+
}
143+
}
144+
145+
function writeIndexFile(indexData) {
146+
const indexPath = path.join(__dirname, 'index.json');
147+
try {
148+
fs.writeFileSync(indexPath, JSON.stringify(indexData, null, 2), 'utf-8');
149+
console.log('Successfully wrote index.json');
150+
} catch (error) {
151+
console.error('Error writing index.json:', error);
152+
}
153+
}
154+
155+
function combineIndexes(dir) {
156+
const indexData = loadIndexTemplate();
157+
const documents = readAllMarkdownFiles(dir);
158+
159+
// Add the documents array with new content
160+
indexData.documents = documents;
161+
writeIndexFile(indexData);
162+
}
163+
164+
// Replace console.log with combineIndexes call
165+
combineIndexes(path.join(__dirname, 'docs'));
166+
167+
module.exports = readAllMarkdownFiles;
168+

index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ class DocumentService {
459459

460460
processImages(content, basePath) {
461461
return content.replace(/!\[\[(.*?)\]\]/g, (match, filename) => {
462-
const mediaPath = `${basePath}/images/${filename}`;
462+
const mediaPath = `./docs/images/${filename}`;
463463

464464
if (filename.toLowerCase().endsWith('.mp4')) {
465465
return `\n<video controls width="100%">

0 commit comments

Comments
 (0)