@kenjura/ursa 0.43.0 → 0.44.0
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/CHANGELOG.md +5 -0
- package/package.json +1 -1
- package/src/helper/sectionExtractor.js +76 -0
- package/src/jobs/generate.js +10 -0
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract sections from markdown content based on headings
|
|
3
|
+
* Creates a hierarchical structure of sections
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Extract sections from markdown content
|
|
8
|
+
* @param {string} content - The markdown content
|
|
9
|
+
* @returns {Array} Array of section objects with name and optional children
|
|
10
|
+
*/
|
|
11
|
+
export function extractSections(content) {
|
|
12
|
+
if (!content) return [];
|
|
13
|
+
|
|
14
|
+
// Match all markdown headings (# to ######)
|
|
15
|
+
// Handles both "# Heading" and "#Heading" formats
|
|
16
|
+
const headingRegex = /^(#{1,6})\s*(.+?)$/gm;
|
|
17
|
+
|
|
18
|
+
const headings = [];
|
|
19
|
+
let match;
|
|
20
|
+
|
|
21
|
+
while ((match = headingRegex.exec(content)) !== null) {
|
|
22
|
+
const level = match[1].length; // Number of # characters
|
|
23
|
+
const name = match[2].trim();
|
|
24
|
+
headings.push({ level, name });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (headings.length === 0) return [];
|
|
28
|
+
|
|
29
|
+
// Build hierarchical structure
|
|
30
|
+
return buildSectionTree(headings);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Build a hierarchical tree from flat heading list
|
|
35
|
+
* @param {Array} headings - Array of {level, name} objects
|
|
36
|
+
* @returns {Array} Hierarchical section tree
|
|
37
|
+
*/
|
|
38
|
+
function buildSectionTree(headings) {
|
|
39
|
+
const root = { level: 0, children: [] };
|
|
40
|
+
const stack = [root];
|
|
41
|
+
|
|
42
|
+
for (const heading of headings) {
|
|
43
|
+
const section = { name: heading.name, level: heading.level, children: [] };
|
|
44
|
+
|
|
45
|
+
// Pop stack until we find a parent with lower level
|
|
46
|
+
while (stack.length > 1 && stack[stack.length - 1].level >= heading.level) {
|
|
47
|
+
stack.pop();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Add to parent's children
|
|
51
|
+
const parent = stack[stack.length - 1];
|
|
52
|
+
parent.children.push(section);
|
|
53
|
+
|
|
54
|
+
// Push this section onto stack (it might have children)
|
|
55
|
+
stack.push(section);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Clean up: remove level and empty children arrays
|
|
59
|
+
cleanupTree(root.children);
|
|
60
|
+
|
|
61
|
+
return root.children;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Remove level property and empty children arrays from the tree
|
|
66
|
+
*/
|
|
67
|
+
function cleanupTree(sections) {
|
|
68
|
+
for (const section of sections) {
|
|
69
|
+
delete section.level;
|
|
70
|
+
if (section.children && section.children.length > 0) {
|
|
71
|
+
cleanupTree(section.children);
|
|
72
|
+
} else {
|
|
73
|
+
delete section.children;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
package/src/jobs/generate.js
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
markInactiveLinks,
|
|
22
22
|
} from "../helper/linkValidator.js";
|
|
23
23
|
import { getAndIncrementBuildId } from "../helper/ursaConfig.js";
|
|
24
|
+
import { extractSections } from "../helper/sectionExtractor.js";
|
|
24
25
|
|
|
25
26
|
// Helper function to build search index from processed files
|
|
26
27
|
function buildSearchIndex(jsonCache, source, output) {
|
|
@@ -230,12 +231,16 @@ export async function generate({
|
|
|
230
231
|
dirname: dir,
|
|
231
232
|
basename: base,
|
|
232
233
|
});
|
|
234
|
+
// Extract sections for markdown files
|
|
235
|
+
const sections = type === '.md' ? extractSections(rawBody) : [];
|
|
236
|
+
|
|
233
237
|
jsonCache.set(file, {
|
|
234
238
|
name: base,
|
|
235
239
|
url,
|
|
236
240
|
contents: rawBody,
|
|
237
241
|
bodyHtml: body,
|
|
238
242
|
metadata: meta,
|
|
243
|
+
sections,
|
|
239
244
|
transformedMetadata: '',
|
|
240
245
|
});
|
|
241
246
|
return; // Skip regenerating this file
|
|
@@ -307,6 +312,10 @@ export async function generate({
|
|
|
307
312
|
// json
|
|
308
313
|
|
|
309
314
|
const jsonOutputFilename = outputFilename.replace(".html", ".json");
|
|
315
|
+
|
|
316
|
+
// Extract sections for markdown files
|
|
317
|
+
const sections = type === '.md' ? extractSections(rawBody) : [];
|
|
318
|
+
|
|
310
319
|
const jsonObject = {
|
|
311
320
|
name: base,
|
|
312
321
|
url,
|
|
@@ -314,6 +323,7 @@ export async function generate({
|
|
|
314
323
|
// bodyLessMeta: bodyLessMeta,
|
|
315
324
|
bodyHtml: body,
|
|
316
325
|
metadata: meta,
|
|
326
|
+
sections,
|
|
317
327
|
transformedMetadata,
|
|
318
328
|
// html: finalHtml,
|
|
319
329
|
};
|