@kenjura/ursa 0.50.0 → 0.51.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/jobs/generate.js +47 -9
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
package/src/jobs/generate.js
CHANGED
|
@@ -309,6 +309,15 @@ export async function generate({
|
|
|
309
309
|
(filename) => isDirectory(filename)
|
|
310
310
|
)).filter((filename) => !filename.match(hiddenOrSystemDirs) && !isFolderHidden(filename, source));
|
|
311
311
|
|
|
312
|
+
// Build set of existing HTML files in source directory (these should not be overwritten)
|
|
313
|
+
const htmlExtensions = /\.html$/;
|
|
314
|
+
const existingHtmlFiles = new Set(
|
|
315
|
+
allSourceFilenames
|
|
316
|
+
.filter(f => f.match(htmlExtensions) && !f.match(hiddenOrSystemDirs))
|
|
317
|
+
.map(f => f.replace(source, '')) // Store relative paths for easy lookup
|
|
318
|
+
);
|
|
319
|
+
progress.log(`Found ${existingHtmlFiles.size} existing HTML files in source`);
|
|
320
|
+
|
|
312
321
|
// Build set of valid internal paths for link validation (must be before menu)
|
|
313
322
|
// Pass directories to ensure folder links are valid (auto-index generates index.html for all folders)
|
|
314
323
|
const validPaths = buildValidPaths(allSourceFilenamesThatAreArticles, source, allSourceFilenamesThatAreDirectories);
|
|
@@ -391,6 +400,14 @@ export async function generate({
|
|
|
391
400
|
content: '' // Content excerpts built lazily to save memory
|
|
392
401
|
});
|
|
393
402
|
|
|
403
|
+
// Check if a corresponding .html file already exists in source directory
|
|
404
|
+
const outputHtmlRelative = relativePath.startsWith('/') ? relativePath.slice(1) : relativePath;
|
|
405
|
+
if (existingHtmlFiles.has(outputHtmlRelative)) {
|
|
406
|
+
progress.log(`⚠️ Warning: Skipping ${shortFile} - would overwrite existing ${outputHtmlRelative} in source`);
|
|
407
|
+
skippedCount++;
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
|
|
394
411
|
// Check if file needs regeneration
|
|
395
412
|
const needsRegen = _clean || needsRegeneration(file, rawBody, hashCache);
|
|
396
413
|
|
|
@@ -600,16 +617,23 @@ export async function generate({
|
|
|
600
617
|
// Clear directory index cache to free memory before processing static files
|
|
601
618
|
dirIndexCache.clear();
|
|
602
619
|
|
|
603
|
-
// copy all static files (
|
|
620
|
+
// copy all static files (images and existing HTML files) with batched concurrency
|
|
604
621
|
const imageExtensions = /\.(jpg|jpeg|png|gif|webp|svg|ico)/; // static asset extensions
|
|
605
622
|
const allSourceFilenamesThatAreImages = allSourceFilenames.filter(
|
|
606
623
|
(filename) => filename.match(imageExtensions)
|
|
607
624
|
);
|
|
608
|
-
|
|
625
|
+
|
|
626
|
+
// Also copy existing HTML files from source to output (they're treated as static)
|
|
627
|
+
const allSourceFilenamesThatAreHtml = allSourceFilenames.filter(
|
|
628
|
+
(filename) => filename.match(/\.html$/) && !filename.match(hiddenOrSystemDirs)
|
|
629
|
+
);
|
|
630
|
+
|
|
631
|
+
const allStaticFiles = [...allSourceFilenamesThatAreImages, ...allSourceFilenamesThatAreHtml];
|
|
632
|
+
const totalStatic = allStaticFiles.length;
|
|
609
633
|
let processedStatic = 0;
|
|
610
634
|
let copiedStatic = 0;
|
|
611
|
-
progress.log(`Processing ${totalStatic} static files...`);
|
|
612
|
-
await processBatched(
|
|
635
|
+
progress.log(`Processing ${totalStatic} static files (${allSourceFilenamesThatAreImages.length} images, ${allSourceFilenamesThatAreHtml.length} HTML)...`);
|
|
636
|
+
await processBatched(allStaticFiles, async (file) => {
|
|
613
637
|
try {
|
|
614
638
|
processedStatic++;
|
|
615
639
|
const shortFile = file.replace(source, '');
|
|
@@ -639,7 +663,7 @@ export async function generate({
|
|
|
639
663
|
|
|
640
664
|
// Automatic index generation for folders without index.html
|
|
641
665
|
progress.log(`Checking for missing index files...`);
|
|
642
|
-
await generateAutoIndices(output, allSourceFilenamesThatAreDirectories, source, templates, menu, footer, allSourceFilenamesThatAreArticles, copiedCssFiles);
|
|
666
|
+
await generateAutoIndices(output, allSourceFilenamesThatAreDirectories, source, templates, menu, footer, allSourceFilenamesThatAreArticles, copiedCssFiles, existingHtmlFiles);
|
|
643
667
|
|
|
644
668
|
// Save the hash cache to .ursa folder in source directory
|
|
645
669
|
if (hashCache.size > 0) {
|
|
@@ -706,8 +730,9 @@ export async function generate({
|
|
|
706
730
|
* @param {string} footer - Footer HTML
|
|
707
731
|
* @param {string[]} generatedArticles - List of source article paths that were generated
|
|
708
732
|
* @param {Set<string>} copiedCssFiles - Set of CSS files already copied to output
|
|
733
|
+
* @param {Set<string>} existingHtmlFiles - Set of existing HTML files in source (relative paths)
|
|
709
734
|
*/
|
|
710
|
-
async function generateAutoIndices(output, directories, source, templates, menu, footer, generatedArticles, copiedCssFiles) {
|
|
735
|
+
async function generateAutoIndices(output, directories, source, templates, menu, footer, generatedArticles, copiedCssFiles, existingHtmlFiles) {
|
|
711
736
|
// Alternate index file names to look for (in priority order)
|
|
712
737
|
const INDEX_ALTERNATES = ['_index.html', 'home.html', '_home.html'];
|
|
713
738
|
|
|
@@ -736,6 +761,7 @@ async function generateAutoIndices(output, directories, source, templates, menu,
|
|
|
736
761
|
|
|
737
762
|
let generatedCount = 0;
|
|
738
763
|
let renamedCount = 0;
|
|
764
|
+
let skippedHtmlCount = 0;
|
|
739
765
|
|
|
740
766
|
for (const dir of outputDirs) {
|
|
741
767
|
const indexPath = join(dir, 'index.html');
|
|
@@ -745,7 +771,15 @@ async function generateAutoIndices(output, directories, source, templates, menu,
|
|
|
745
771
|
continue;
|
|
746
772
|
}
|
|
747
773
|
|
|
748
|
-
//
|
|
774
|
+
// Check if there's an existing index.html in the source directory (don't overwrite it)
|
|
775
|
+
const sourceDir = dir.replace(outputNorm, sourceNorm);
|
|
776
|
+
const relativeIndexPath = join(sourceDir, 'index.html').replace(sourceNorm + '/', '');
|
|
777
|
+
if (existingHtmlFiles && existingHtmlFiles.has(relativeIndexPath)) {
|
|
778
|
+
skippedHtmlCount++;
|
|
779
|
+
continue; // Don't overwrite existing source HTML
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// Skip if index.html already exists in output (e.g., created by previous run)
|
|
749
783
|
if (existsSync(indexPath)) {
|
|
750
784
|
continue;
|
|
751
785
|
}
|
|
@@ -860,8 +894,12 @@ async function generateAutoIndices(output, directories, source, templates, menu,
|
|
|
860
894
|
}
|
|
861
895
|
}
|
|
862
896
|
|
|
863
|
-
if (generatedCount > 0 || renamedCount > 0) {
|
|
864
|
-
|
|
897
|
+
if (generatedCount > 0 || renamedCount > 0 || skippedHtmlCount > 0) {
|
|
898
|
+
let summary = `${generatedCount} generated, ${renamedCount} promoted`;
|
|
899
|
+
if (skippedHtmlCount > 0) {
|
|
900
|
+
summary += `, ${skippedHtmlCount} skipped (existing HTML)`;
|
|
901
|
+
}
|
|
902
|
+
progress.done('Auto-index', summary);
|
|
865
903
|
} else {
|
|
866
904
|
progress.log(`Auto-index: All folders already have index.html`);
|
|
867
905
|
}
|