ultimate-jekyll-manager 0.0.136 → 0.0.137

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.
@@ -42,6 +42,7 @@ module.exports = async function (options) {
42
42
  options.updateBundle = options.updateBundle !== 'false';
43
43
  options.publishGitHubToken = options.publishGitHubToken !== 'false';
44
44
  options.updateGitHubPages = options.updateGitHubPages !== 'false';
45
+ options.deduplicatePosts = options.deduplicatePosts !== 'false';
45
46
 
46
47
  // Log
47
48
  logger.log(`Welcome to ${package.name} v${package.version}!`);
@@ -125,6 +126,11 @@ module.exports = async function (options) {
125
126
  if (options.updateBundle && !Manager.isServer()) {
126
127
  await updateBundle();
127
128
  }
129
+
130
+ // Deduplicate posts (remove duplicate posts with same slug but different dates)
131
+ if (options.deduplicatePosts) {
132
+ await deduplicatePosts();
133
+ }
128
134
  } catch (e) {
129
135
  // Throw error
130
136
  throw e;
@@ -599,7 +605,7 @@ async function updateGitHubPages(options) {
599
605
  owner,
600
606
  repo,
601
607
  source: sourceConfig,
602
- };
608
+ };
603
609
 
604
610
  // Add custom domain if available and not github.io domain
605
611
  if (customDomain && !customDomain.includes('github.io')) {
@@ -654,3 +660,117 @@ async function updateGitHubPages(options) {
654
660
  // Don't throw - this is not critical for setup to continue
655
661
  }
656
662
  }
663
+
664
+ // Deduplicate posts - removes duplicate posts with same slug but different dates
665
+ // Keeps the ORIGINAL (oldest) post and removes newer duplicates
666
+ async function deduplicatePosts() {
667
+ logger.log('🔍 Checking for duplicate posts...');
668
+
669
+ // Find all post files in src/_posts
670
+ const postsGlob = 'src/_posts/**/*.{md,markdown,html}';
671
+ const postFiles = glob(postsGlob, { nodir: true });
672
+
673
+ if (postFiles.length === 0) {
674
+ logger.log('No posts found');
675
+ return;
676
+ }
677
+
678
+ logger.log(`Found ${postFiles.length} post files`);
679
+
680
+ // Group posts by slug (filename without date prefix)
681
+ const postsBySlug = {};
682
+
683
+ for (const filePath of postFiles) {
684
+ const filename = path.basename(filePath);
685
+
686
+ // Jekyll post format: YYYY-MM-DD-slug.ext
687
+ const match = filename.match(/^(\d{4}-\d{2}-\d{2})-(.+)\.(md|markdown|html)$/);
688
+
689
+ if (!match) {
690
+ continue;
691
+ }
692
+
693
+ const [, dateStr, slug, ext] = match;
694
+ const date = new Date(dateStr);
695
+
696
+ if (!postsBySlug[slug]) {
697
+ postsBySlug[slug] = [];
698
+ }
699
+
700
+ postsBySlug[slug].push({
701
+ filePath,
702
+ filename,
703
+ date,
704
+ dateStr,
705
+ slug,
706
+ ext,
707
+ });
708
+ }
709
+
710
+ // Find duplicates and keep only the ORIGINAL (oldest)
711
+ let removedCount = 0;
712
+ const duplicates = [];
713
+
714
+ for (const [slug, posts] of Object.entries(postsBySlug)) {
715
+ if (posts.length <= 1) {
716
+ continue;
717
+ }
718
+
719
+ // Sort by date ascending (oldest first)
720
+ posts.sort((a, b) => a.date - b.date);
721
+
722
+ // Keep the oldest (original), mark the rest for removal
723
+ const [original, ...newer] = posts;
724
+
725
+ logger.log(`Found ${posts.length} posts with slug "${slug}":`);
726
+ logger.log(` ✅ Keeping original: ${original.filename} (${original.dateStr})`);
727
+
728
+ for (const post of newer) {
729
+ logger.log(` ❌ Removing duplicate: ${post.filename} (${post.dateStr})`);
730
+
731
+ // Remove the duplicate post file
732
+ try {
733
+ jetpack.remove(post.filePath);
734
+ removedCount++;
735
+
736
+ // Also remove the associated images folder (src/assets/images/blog/post-SLUG)
737
+ const imageFolder = `src/assets/images/blog/post-${post.slug}`;
738
+ if (jetpack.exists(imageFolder)) {
739
+ jetpack.remove(imageFolder);
740
+ logger.log(` 🗑️ Removed image folder: ${imageFolder}`);
741
+ }
742
+
743
+ duplicates.push({
744
+ kept: original.filename,
745
+ removed: post.filename,
746
+ removedPath: post.filePath,
747
+ slug,
748
+ });
749
+ } catch (error) {
750
+ logger.error(`Failed to remove ${post.filePath}:`, error);
751
+ }
752
+ }
753
+ }
754
+
755
+ // Log summary
756
+ if (removedCount > 0) {
757
+ logger.log(`✅ Removed ${removedCount} duplicate post(s)`);
758
+
759
+ // Save report
760
+ const reportDir = path.join(rootPathProject, '.temp/deduplicate');
761
+ jetpack.dir(reportDir);
762
+
763
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
764
+ const reportPath = path.join(reportDir, `duplicates-${timestamp}.json`);
765
+
766
+ jetpack.write(reportPath, JSON.stringify({
767
+ timestamp: new Date().toISOString(),
768
+ removedCount,
769
+ duplicates,
770
+ }, null, 2));
771
+
772
+ logger.log(`Report saved to: ${reportPath}`);
773
+ } else {
774
+ logger.log('✅ No duplicate posts found');
775
+ }
776
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultimate-jekyll-manager",
3
- "version": "0.0.136",
3
+ "version": "0.0.137",
4
4
  "description": "Ultimate Jekyll dependency manager",
5
5
  "main": "dist/index.js",
6
6
  "exports": {