UNPKG

@agility/cli

Version:

Agility CLI for working with your content. (Public Beta)

540 lines 25 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.SitemapHierarchy = void 0; var fs = __importStar(require("fs")); var path = __importStar(require("path")); var state_1 = require("../../../core/state"); /** * Load and parse sitemap hierarchy for hierarchical page chain analysis */ var SitemapHierarchy = /** @class */ (function () { function SitemapHierarchy() { // Configuration now comes from state internally } SitemapHierarchy.prototype.loadAllSitemaps = function (guid, locale) { var _this = this; var rootPath = state_1.state.rootPath, sourceGuid = state_1.state.sourceGuid; var sitemapDir = path.join(rootPath, guid, locale, 'nestedsitemap'); var sitemaps = {}; fs.readdirSync(sitemapDir).forEach(function (fileName) { if (!fileName.endsWith('.json')) { return; // Skip non-JSON files } var channel = path.basename(fileName, '.json'); sitemaps[channel] = _this.loadNestedSitemap(path.join(sitemapDir, fileName)); }); return sitemaps; }; /** * Load nested sitemap from the file system */ SitemapHierarchy.prototype.loadNestedSitemap = function (filePath) { try { if (!fs.existsSync(filePath)) { console.warn("Nested sitemap not found at: ".concat(filePath)); return null; } var sitemapData = fs.readFileSync(filePath, 'utf8'); var sitemap = JSON.parse(sitemapData); // Loaded nested sitemap (silent) return sitemap; } catch (error) { console.error("Error loading nested sitemap: ".concat(error.message)); return null; } }; /** * Build page hierarchy map from nested sitemap */ SitemapHierarchy.prototype.buildPageHierarchy = function (sitemap) { var hierarchy = {}; var processNode = function (node) { if (node.children && node.children.length > 0) { // This node has children hierarchy[node.pageID] = node.children.map(function (child) { return child.pageID; }); // Recursively process children node.children.forEach(function (child) { return processNode(child); }); } }; sitemap.forEach(function (node) { return processNode(node); }); return hierarchy; }; /** * Group pages hierarchically based on sitemap structure */ SitemapHierarchy.prototype.groupPagesHierarchically = function (pages, hierarchy) { var _this = this; var processedPages = new Set(); var hierarchicalGroups = []; // Process each page that has children pages.forEach(function (page) { if (!processedPages.has(page.pageID) && hierarchy[page.pageID]) { // This page has children, create a group for it var group = _this.buildHierarchicalGroup(page, pages, hierarchy, processedPages); hierarchicalGroups.push(group); } }); // Process remaining pages that don't have children and aren't children of processed pages pages.forEach(function (page) { if (!processedPages.has(page.pageID)) { // This is an orphaned page (no children, not a child of any processed page) var group = { rootPage: page, childPages: [], allPageIds: new Set([page.pageID]) }; hierarchicalGroups.push(group); processedPages.add(page.pageID); } }); return hierarchicalGroups; }; /** * Find the parent page ID for a given page (only if parent exists in our page list) */ SitemapHierarchy.prototype.findParentPageId = function (pageId, hierarchy, pages) { var _loop_1 = function (parentId, childIds) { if (childIds.includes(pageId)) { // Check if the parent exists in our page list var parentExists = pages.some(function (p) { return p.pageID === parseInt(parentId); }); if (parentExists) { return { value: parseInt(parentId) }; } } }; for (var _i = 0, _a = Object.entries(hierarchy); _i < _a.length; _i++) { var _b = _a[_i], parentId = _b[0], childIds = _b[1]; var state_2 = _loop_1(parentId, childIds); if (typeof state_2 === "object") return state_2.value; } return null; }; /** * Build a hierarchical group starting from a root page */ SitemapHierarchy.prototype.buildHierarchicalGroup = function (rootPage, allPages, hierarchy, processedPages) { var group = { rootPage: rootPage, childPages: [], allPageIds: new Set([rootPage.pageID]) }; // Mark root as processed processedPages.add(rootPage.pageID); // Collect ALL descendants with unlimited nesting levels this.collectAllDescendants(rootPage.pageID, allPages, hierarchy, group, processedPages); return group; }; /** * Collect all descendants with unlimited nesting levels (not just direct children) * This enables proper display of deep hierarchies like PageID:A → PageID:B → PageID:C */ SitemapHierarchy.prototype.collectAllDescendants = function (parentPageId, allPages, hierarchy, group, processedPages) { var _this = this; var directChildIds = hierarchy[parentPageId] || []; directChildIds.forEach(function (childId) { var childPage = allPages.find(function (p) { return p.pageID === childId; }); if (childPage && !processedPages.has(childId)) { // Add this child to the current level group.childPages.push(childPage); group.allPageIds.add(childId); processedPages.add(childId); // Recursively collect ALL descendants (grandchildren, great-grandchildren, etc.) _this.collectAllDescendants(childId, allPages, hierarchy, group, processedPages); } }); }; /** * Get orphaned pages (pages not in any hierarchical group) */ SitemapHierarchy.prototype.getOrphanedPages = function (pages, hierarchicalGroups) { var allProcessedIds = new Set(); hierarchicalGroups.forEach(function (group) { group.allPageIds.forEach(function (id) { return allProcessedIds.add(id); }); }); return pages.filter(function (page) { return !allProcessedIds.has(page.pageID); }); }; /** * Debug: Log hierarchy structure */ SitemapHierarchy.prototype.debugLogHierarchy = function (hierarchy) { console.log("\uD83D\uDD27 [DEBUG] Page hierarchy structure:"); Object.entries(hierarchy).forEach(function (_a) { var parentId = _a[0], childIds = _a[1]; console.log(" Parent ".concat(parentId, " has children: ").concat(childIds.join(', '))); }); }; /** * ✅ NEW: Find page parent from source sitemap with comprehensive lookup * Handles both template pages and dynamic page instances */ SitemapHierarchy.prototype.findPageParentInSourceSitemap = function (pageId, pageName, channelName) { try { var sitemap = this.loadNestedSitemap(channelName); if (!sitemap || sitemap.length === 0) { return { parentId: null, parentName: null, foundIn: 'no-sitemap' }; } // Recursive function to search through sitemap var searchSitemap_1 = function (nodes, parentNode) { if (parentNode === void 0) { parentNode = null; } for (var _i = 0, nodes_1 = nodes; _i < nodes_1.length; _i++) { var node = nodes_1[_i]; // Check if this node is our target page if (node.pageID === pageId || node.name === pageName) { if (parentNode) { console.log("\uD83C\uDFAF [DEBUG] Found ".concat(pageName, " (ID:").concat(pageId, ") under parent ").concat(parentNode.name, " (ID:").concat(parentNode.pageID, ")")); return { parentId: parentNode.pageID, parentName: parentNode.name, foundIn: 'direct-match' }; } else { console.log("\uD83C\uDFE0 [DEBUG] Found ".concat(pageName, " (ID:").concat(pageId, ") at root level")); return { parentId: null, parentName: null, foundIn: 'root-level' }; } } // Check if this node has children (dynamic page instances) if (node.children && node.children.length > 0) { // For dynamic pages: check if any child has same pageID as template var dynamicMatch = node.children.find(function (child) { return child.pageID === pageId; }); if (dynamicMatch) { console.log("\uD83C\uDFAF [DEBUG] Found dynamic page ".concat(pageName, " (ID:").concat(pageId, ") under parent ").concat(node.name, " (ID:").concat(node.pageID, ")")); return { parentId: node.pageID, parentName: node.name, foundIn: 'dynamic-child' }; } // Recursively search children var childResult = searchSitemap_1(node.children, node); if (childResult.parentId !== null) { return childResult; } } } return { parentId: null, parentName: null, foundIn: 'not-found' }; }; var result = searchSitemap_1(sitemap); console.log("\uD83D\uDCCD [DEBUG] Parent lookup result for ".concat(pageName, ":"), result); return result; } catch (error) { console.error("\u274C [DEBUG] Error looking up parent for ".concat(pageName, ":"), error.message); return { parentId: null, parentName: null, foundIn: 'error' }; } }; /** * ✅ NEW: Enhanced hierarchy build that handles dynamic pages correctly */ SitemapHierarchy.prototype.buildPageHierarchyWithDynamicSupport = function (sitemap) { var hierarchy = {}; var processNode = function (node, parentNode) { if (parentNode === void 0) { parentNode = null; } // If this node has children, add them to hierarchy if (node.children && node.children.length > 0) { hierarchy[node.pageID] = node.children.map(function (child) { return child.pageID; }); // Process children recursively node.children.forEach(function (child) { return processNode(child, node); }); } // Special handling for dynamic pages // If this node has dynamic children (contentID present), also map those if (node.children) { node.children.forEach(function (child) { if (child.contentID) { // This is a dynamic page instance - ensure it knows its parent if (!hierarchy[node.pageID]) { hierarchy[node.pageID] = []; } if (!hierarchy[node.pageID].includes(child.pageID)) { hierarchy[node.pageID].push(child.pageID); } } }); } }; sitemap.forEach(function (node) { return processNode(node); }); return hierarchy; }; /** * Calculate depth level for each page in the hierarchy * Depth 0 = root pages (no parents), Depth 1 = direct children, etc. */ SitemapHierarchy.prototype.calculatePageDepths = function (pages, hierarchy) { var pageDepths = new Map(); var visited = new Set(); // Build reverse lookup: child → parent var childToParent = new Map(); Object.entries(hierarchy).forEach(function (_a) { var parentIdStr = _a[0], childIds = _a[1]; var parentId = parseInt(parentIdStr); childIds.forEach(function (childId) { childToParent.set(childId, parentId); }); }); // Calculate depth recursively for each page var calculateDepth = function (pageId) { if (visited.has(pageId)) { // Circular reference detected - return high depth to process early console.warn("Circular reference detected for page ".concat(pageId)); return 999; } if (pageDepths.has(pageId)) { return pageDepths.get(pageId); } visited.add(pageId); var parentId = childToParent.get(pageId); if (!parentId) { // Root page (no parent) pageDepths.set(pageId, 0); visited.delete(pageId); return 0; } // Parent exists - depth is parent's depth + 1 var parentDepth = calculateDepth(parentId); var depth = parentDepth + 1; pageDepths.set(pageId, depth); visited.delete(pageId); return depth; }; // Calculate depth for all pages pages.forEach(function (page) { calculateDepth(page.pageID); }); return pageDepths; }; /** * Get pages grouped by depth level * Returns map of depth → pages at that depth */ SitemapHierarchy.prototype.getPagesByDepth = function (pages, pageDepths) { var pagesByDepth = new Map(); pages.forEach(function (page) { var depth = pageDepths.get(page.pageID) || 0; if (!pagesByDepth.has(depth)) { pagesByDepth.set(depth, []); } pagesByDepth.get(depth).push(page); }); return pagesByDepth; }; /** * Generate dependency-safe page processing order * Returns pages ordered by depth (shallowest first) so parents are processed before children */ SitemapHierarchy.prototype.getProcessingOrder = function (pages, hierarchy) { // Calculate page depths var pageDepths = this.calculatePageDepths(pages, hierarchy); // Group pages by depth var pagesByDepth = this.getPagesByDepth(pages, pageDepths); // Sort depth levels in ascending order (shallowest first = parents before children) var sortedDepths = Array.from(pagesByDepth.keys()).sort(function (a, b) { return a - b; }); // Build ordered array with shallowest pages first (parents before children) var orderedPages = []; sortedDepths.forEach(function (depth) { var pagesAtDepth = pagesByDepth.get(depth) || []; // Sort pages within same depth by pageID for consistency pagesAtDepth.sort(function (a, b) { return a.pageID - b.pageID; }); orderedPages.push.apply(orderedPages, pagesAtDepth); }); // Page processing order calculated (silent) return { orderedPages: orderedPages, depthInfo: pageDepths }; }; /** * Validate page processing order is dependency-safe * Ensures no page is processed before its parent */ SitemapHierarchy.prototype.validateProcessingOrder = function (orderedPages, hierarchy) { var processedPageIds = new Set(); // Build reverse lookup: child → parent var childToParent = new Map(); Object.entries(hierarchy).forEach(function (_a) { var parentIdStr = _a[0], childIds = _a[1]; var parentId = parseInt(parentIdStr); childIds.forEach(function (childId) { childToParent.set(childId, parentId); }); }); for (var _i = 0, orderedPages_1 = orderedPages; _i < orderedPages_1.length; _i++) { var page = orderedPages_1[_i]; var parentId = childToParent.get(page.pageID); if (parentId && !processedPageIds.has(parentId)) { // This page's parent hasn't been processed yet - order is invalid console.error("\u274C Invalid processing order: Page ".concat(page.pageID, " scheduled before parent ").concat(parentId)); return false; } processedPageIds.add(page.pageID); } // Processing order validation passed (silent) return true; }; /** * Extract sibling ordering information from source sitemap * Returns a map of pageID → nextSiblingPageID for proper insertion order */ SitemapHierarchy.prototype.extractSiblingOrderFromSitemap = function (sitemap) { var siblingOrderMap = new Map(); var processSiblings = function (siblings, depth) { if (depth === void 0) { depth = 0; } for (var i = 0; i < siblings.length; i++) { var currentPage = siblings[i]; var nextSibling = i < siblings.length - 1 ? siblings[i + 1] : null; // Map current page to its next sibling (or null if last) siblingOrderMap.set(currentPage.pageID, (nextSibling === null || nextSibling === void 0 ? void 0 : nextSibling.pageID) || null); // Process child pages recursively if (currentPage.children && currentPage.children.length > 0) { processSiblings(currentPage.children, depth + 1); } } }; processSiblings(sitemap, 0); return siblingOrderMap; }; /** * Get the pageID that should come BEFORE the specified page (for insertBefore parameter) * FIXED: Returns the NEXT sibling (what this page should go before), not the previous sibling */ SitemapHierarchy.prototype.getInsertBeforePageId = function (pageId, siblingOrder) { // FIXED: Return the next sibling directly - this page should go BEFORE its next sibling var nextSiblingId = siblingOrder.get(pageId) || null; if (nextSiblingId) { return nextSiblingId; } else { return null; // No next sibling found (page is last in its group, will place at end) } }; /** * Build comprehensive page ordering data including parent-child and sibling relationships */ SitemapHierarchy.prototype.buildPageOrderingData = function (sitemap) { var hierarchy = this.buildPageHierarchyWithDynamicSupport(sitemap); var siblingOrder = this.extractSiblingOrderFromSitemap(sitemap); // Build parent-to-children mapping for quick lookup var parentToChildrenMap = new Map(); Object.entries(hierarchy).forEach(function (_a) { var parentIdStr = _a[0], childIds = _a[1]; var parentId = parseInt(parentIdStr); parentToChildrenMap.set(parentId, childIds); }); return { hierarchy: hierarchy, siblingOrder: siblingOrder, parentToChildrenMap: parentToChildrenMap }; }; /** * Get processing order that preserves both parent-child dependencies AND sibling order */ SitemapHierarchy.prototype.getOrderedProcessingSequence = function (pages, sitemap) { var _this = this; var orderingData = this.buildPageOrderingData(sitemap); var hierarchy = orderingData.hierarchy; // Get dependency-safe order (parents before children) var orderedPages = this.getProcessingOrder(pages, hierarchy).orderedPages; // Within each depth level, sort by sibling order var pageDepths = this.calculatePageDepths(pages, hierarchy); var pagesByDepth = this.getPagesByDepth(pages, pageDepths); // Rebuild ordered pages respecting sibling order within each depth var finalOrderedPages = []; var sortedDepths = Array.from(pagesByDepth.keys()).sort(function (a, b) { return a - b; }); sortedDepths.forEach(function (depth) { var pagesAtDepth = pagesByDepth.get(depth) || []; // Group pages by parent for sibling ordering var pagesByParent = new Map(); pagesAtDepth.forEach(function (page) { var parentId = _this.getParentPageId(page.pageID, hierarchy) || -1; if (!pagesByParent.has(parentId)) { pagesByParent.set(parentId, []); } pagesByParent.get(parentId).push(page); }); // Sort each parent group by sibling order pagesByParent.forEach(function (siblings, parentId) { var sortedSiblings = _this.sortPagesBySiblingOrder(siblings, orderingData.siblingOrder); finalOrderedPages.push.apply(finalOrderedPages, sortedSiblings); }); }); return { orderedPages: finalOrderedPages, orderingData: orderingData }; }; /** * Sort pages by their sibling order from the sitemap */ SitemapHierarchy.prototype.sortPagesBySiblingOrder = function (pages, siblingOrder) { // Create a map to track the position of each page in the sibling order var pagePositions = new Map(); // Build position map by following the sibling chain var position = 0; var currentPageId = null; // Find the first page (one that is not a next sibling of any other page) var allNextSiblings = new Set(Array.from(siblingOrder.values()).filter(function (id) { return id !== null; })); var firstPage = pages.find(function (page) { return !allNextSiblings.has(page.pageID); }); if (firstPage) { currentPageId = firstPage.pageID; // Follow the sibling chain to assign positions while (currentPageId !== null) { pagePositions.set(currentPageId, position++); currentPageId = siblingOrder.get(currentPageId) || null; } } // Sort pages by their positions (pages without positions go to end) return pages.sort(function (a, b) { var _a, _b; var posA = (_a = pagePositions.get(a.pageID)) !== null && _a !== void 0 ? _a : 9999; var posB = (_b = pagePositions.get(b.pageID)) !== null && _b !== void 0 ? _b : 9999; return posA - posB; }); }; /** * Get parent page ID for a given page */ SitemapHierarchy.prototype.getParentPageId = function (pageId, hierarchy) { for (var _i = 0, _a = Object.entries(hierarchy); _i < _a.length; _i++) { var _b = _a[_i], parentIdStr = _b[0], childIds = _b[1]; if (childIds.includes(pageId)) { return parseInt(parentIdStr); } } return null; }; return SitemapHierarchy; }()); exports.SitemapHierarchy = SitemapHierarchy; //# sourceMappingURL=sitemap-hierarchy.js.map