@kenjura/ursa 0.41.0 → 0.43.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 +12 -0
- package/package.json +1 -1
- package/src/helper/automenu.js +8 -1
- package/src/helper/ursaConfig.js +62 -0
- package/src/jobs/generate.js +31 -4
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
package/src/helper/automenu.js
CHANGED
|
@@ -14,6 +14,13 @@ const HOME_ICON = '🏠';
|
|
|
14
14
|
// Index file extensions to check for folder links
|
|
15
15
|
const INDEX_EXTENSIONS = ['.md', '.txt', '.yml', '.yaml'];
|
|
16
16
|
|
|
17
|
+
// Convert filename to display name (e.g., "foo-bar" -> "Foo Bar")
|
|
18
|
+
function toDisplayName(filename) {
|
|
19
|
+
return filename
|
|
20
|
+
.replace(/[-_]/g, ' ') // Replace dashes and underscores with spaces
|
|
21
|
+
.replace(/\b\w/g, c => c.toUpperCase()); // Capitalize first letter of each word
|
|
22
|
+
}
|
|
23
|
+
|
|
17
24
|
function hasIndexFile(dirPath) {
|
|
18
25
|
for (const ext of INDEX_EXTENSIONS) {
|
|
19
26
|
const indexPath = join(dirPath, `index${ext}`);
|
|
@@ -151,7 +158,7 @@ function buildMenuData(tree, source, validPaths, parentPath = '') {
|
|
|
151
158
|
|
|
152
159
|
// Get folder config for custom label and icon
|
|
153
160
|
const folderConfig = hasChildren ? getFolderConfig(item.path) : null;
|
|
154
|
-
const label = folderConfig?.label || baseName;
|
|
161
|
+
const label = folderConfig?.label || toDisplayName(baseName);
|
|
155
162
|
|
|
156
163
|
let rawHref = null;
|
|
157
164
|
if (hasChildren) {
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
|
|
4
|
+
const CONFIG_FILENAME = '.ursa.json';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Get the path to the .ursa.json config file in the source directory
|
|
8
|
+
* @param {string} sourceDir - The source directory path
|
|
9
|
+
* @returns {string} Path to the config file
|
|
10
|
+
*/
|
|
11
|
+
function getConfigPath(sourceDir) {
|
|
12
|
+
return join(sourceDir, CONFIG_FILENAME);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Load the ursa config from .ursa.json
|
|
17
|
+
* @param {string} sourceDir - The source directory path
|
|
18
|
+
* @returns {object} The config object (empty object if file doesn't exist)
|
|
19
|
+
*/
|
|
20
|
+
export function loadUrsaConfig(sourceDir) {
|
|
21
|
+
const configPath = getConfigPath(sourceDir);
|
|
22
|
+
try {
|
|
23
|
+
if (existsSync(configPath)) {
|
|
24
|
+
const content = readFileSync(configPath, 'utf8');
|
|
25
|
+
return JSON.parse(content);
|
|
26
|
+
}
|
|
27
|
+
} catch (e) {
|
|
28
|
+
console.error(`Error reading ${CONFIG_FILENAME}: ${e.message}`);
|
|
29
|
+
}
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Save the ursa config to .ursa.json
|
|
35
|
+
* @param {string} sourceDir - The source directory path
|
|
36
|
+
* @param {object} config - The config object to save
|
|
37
|
+
*/
|
|
38
|
+
export function saveUrsaConfig(sourceDir, config) {
|
|
39
|
+
const configPath = getConfigPath(sourceDir);
|
|
40
|
+
try {
|
|
41
|
+
const content = JSON.stringify(config, null, 2);
|
|
42
|
+
writeFileSync(configPath, content, 'utf8');
|
|
43
|
+
} catch (e) {
|
|
44
|
+
console.error(`Error writing ${CONFIG_FILENAME}: ${e.message}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Get the current build ID and increment it for the next build
|
|
50
|
+
* @param {string} sourceDir - The source directory path
|
|
51
|
+
* @returns {number} The current build ID (starting from 1)
|
|
52
|
+
*/
|
|
53
|
+
export function getAndIncrementBuildId(sourceDir) {
|
|
54
|
+
const config = loadUrsaConfig(sourceDir);
|
|
55
|
+
const currentBuildId = config.buildId || 0;
|
|
56
|
+
const newBuildId = currentBuildId + 1;
|
|
57
|
+
|
|
58
|
+
config.buildId = newBuildId;
|
|
59
|
+
saveUrsaConfig(sourceDir, config);
|
|
60
|
+
|
|
61
|
+
return newBuildId;
|
|
62
|
+
}
|
package/src/jobs/generate.js
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
buildValidPaths,
|
|
21
21
|
markInactiveLinks,
|
|
22
22
|
} from "../helper/linkValidator.js";
|
|
23
|
+
import { getAndIncrementBuildId } from "../helper/ursaConfig.js";
|
|
23
24
|
|
|
24
25
|
// Helper function to build search index from processed files
|
|
25
26
|
function buildSearchIndex(jsonCache, source, output) {
|
|
@@ -128,8 +129,12 @@ export async function generate({
|
|
|
128
129
|
|
|
129
130
|
const menu = await getMenu(allSourceFilenames, source, validPaths);
|
|
130
131
|
|
|
132
|
+
// Get and increment build ID from .ursa.json
|
|
133
|
+
const buildId = getAndIncrementBuildId(resolve(_source));
|
|
134
|
+
console.log(`Build #${buildId}`);
|
|
135
|
+
|
|
131
136
|
// Generate footer content
|
|
132
|
-
const footer = await getFooter(source, _source);
|
|
137
|
+
const footer = await getFooter(source, _source, buildId);
|
|
133
138
|
|
|
134
139
|
// Load content hash cache from .ursa folder in source directory
|
|
135
140
|
let hashCache = new Map();
|
|
@@ -551,8 +556,9 @@ function addTrailingSlash(somePath) {
|
|
|
551
556
|
* Generate footer HTML from footer.md and package.json
|
|
552
557
|
* @param {string} source - resolved source path with trailing slash
|
|
553
558
|
* @param {string} _source - original source path
|
|
559
|
+
* @param {number} buildId - the current build ID
|
|
554
560
|
*/
|
|
555
|
-
async function getFooter(source, _source) {
|
|
561
|
+
async function getFooter(source, _source, buildId) {
|
|
556
562
|
const footerParts = [];
|
|
557
563
|
|
|
558
564
|
// Try to read footer.md from source root
|
|
@@ -607,12 +613,18 @@ async function getFooter(source, _source) {
|
|
|
607
613
|
console.error(`Error reading ursa package.json: ${e.message}`);
|
|
608
614
|
}
|
|
609
615
|
|
|
610
|
-
// Build meta line: version, timestamp, "generated by ursa"
|
|
616
|
+
// Build meta line: version, build id, timestamp, "generated by ursa"
|
|
611
617
|
const metaParts = [];
|
|
612
618
|
if (docPackage?.version) {
|
|
613
619
|
metaParts.push(`v${docPackage.version}`);
|
|
614
620
|
}
|
|
615
|
-
metaParts.push(
|
|
621
|
+
metaParts.push(`build ${buildId}`);
|
|
622
|
+
|
|
623
|
+
// Full date/time in a readable format
|
|
624
|
+
const now = new Date();
|
|
625
|
+
const timestamp = now.toISOString().replace('T', ' ').replace(/\.\d{3}Z$/, ' UTC');
|
|
626
|
+
metaParts.push(timestamp);
|
|
627
|
+
|
|
616
628
|
metaParts.push(`Generated by <a href="https://www.npmjs.com/package/@kenjura/ursa">ursa</a> v${ursaVersion}`);
|
|
617
629
|
|
|
618
630
|
footerParts.push(`<div class="footer-meta">${metaParts.join(' • ')}</div>`);
|
|
@@ -628,5 +640,20 @@ async function getFooter(source, _source) {
|
|
|
628
640
|
}
|
|
629
641
|
}
|
|
630
642
|
|
|
643
|
+
// Try to get git short hash of doc repo (as HTML comment)
|
|
644
|
+
try {
|
|
645
|
+
const { execSync } = await import('child_process');
|
|
646
|
+
const gitHash = execSync('git rev-parse --short HEAD', {
|
|
647
|
+
cwd: resolve(_source),
|
|
648
|
+
encoding: 'utf8',
|
|
649
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
650
|
+
}).trim();
|
|
651
|
+
if (gitHash) {
|
|
652
|
+
footerParts.push(`<!-- git: ${gitHash} -->`);
|
|
653
|
+
}
|
|
654
|
+
} catch (e) {
|
|
655
|
+
// Not a git repo or git not available - silently skip
|
|
656
|
+
}
|
|
657
|
+
|
|
631
658
|
return footerParts.join('\n');
|
|
632
659
|
}
|