UNPKG

@mdfriday/foundry

Version:

The core engine of MDFriday. Convert Markdown and shortcodes into fully themed static sites – Hugo-style, powered by TypeScript.

493 lines 17.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PageMap = exports.PageMapQueryPagesInSectionImpl = exports.PageMapQueryPagesBelowPathImpl = exports.pagePredicates = void 0; exports.addTrailingSlash = addTrailingSlash; const pagetrees_1 = require("./pagetrees"); const pagesource_1 = require("./pagesource"); const type_1 = require("../../paths/type"); const doctree_1 = require("../../../../pkg/doctree"); const sort_1 = require("../vo/sort"); const log_1 = require("../../../../pkg/log"); // Create a domain-specific logger for content operations const log = (0, log_1.getDomainLogger)('content', { component: 'pagemap' }); /** * Path utility functions - simplified implementations */ function addTrailingSlash(path) { if (!path.endsWith("/")) { path += "/"; } return path; } function addLeadingSlash(path) { if (!path.startsWith("/")) { path = "/" + path; } return path; } /** * Ambiguous content node - used for reverse index conflicts */ const ambiguousContentNode = new pagetrees_1.PageTreesNode(); /** * ContentTreeReverseIndexMap - manages reverse index mapping */ class ContentTreeReverseIndexMap { constructor() { this.initOnce = false; this.m = new Map(); } } /** * ContentTreeReverseIndex - reverse index for content tree */ class ContentTreeReverseIndex { constructor(initFn) { this.initFn = initFn; this.contentTreeReverseIndexMap = new ContentTreeReverseIndexMap(); } reset() { this.contentTreeReverseIndexMap = new ContentTreeReverseIndexMap(); } get(key) { if (!this.contentTreeReverseIndexMap.initOnce) { this.contentTreeReverseIndexMap.m = new Map(); this.initFn(this.contentTreeReverseIndexMap.m); this.contentTreeReverseIndexMap.initOnce = true; } return this.contentTreeReverseIndexMap.m.get(key) || null; } } /** * Page predicates - exact replica of Go's pagePredicates */ exports.pagePredicates = { kindPage: (p) => p.kind() === "page", kindSection: (p) => p.kind() === "section", kindHome: (p) => p.kind() === "home", kindTerm: (p) => p.kind() === "term", shouldListLocal: (p) => p.shouldList ? p.shouldList(false) : true, shouldListGlobal: (p) => p.shouldList ? p.shouldList(true) : true, shouldListAny: (p) => p.shouldListAny ? p.shouldListAny() : true, shouldLink: (p) => p.noLink ? !p.noLink() : true }; /** * Implementation of PageMapQueryPagesBelowPath */ class PageMapQueryPagesBelowPathImpl { constructor(path, keyPart, include = exports.pagePredicates.shouldListLocal) { this.path = path; this.keyPart = keyPart; this.include = include; } key() { return this.path + "/" + this.keyPart; } } exports.PageMapQueryPagesBelowPathImpl = PageMapQueryPagesBelowPathImpl; /** * Implementation of PageMapQueryPagesInSection */ class PageMapQueryPagesInSectionImpl extends PageMapQueryPagesBelowPathImpl { constructor(path, keyPart, recursive, includeSelf, index, include) { super(path, keyPart, include); this.recursive = recursive; this.includeSelf = includeSelf; this.index = index; } key() { return "gagesInSection" + "/" + super.key() + "/" + this.recursive.toString() + "/" + this.index.toString() + "/" + this.includeSelf.toString(); } } exports.PageMapQueryPagesInSectionImpl = PageMapQueryPagesInSectionImpl; class PageMap extends pagetrees_1.PageTrees { constructor(pageBuilder) { super(); this.pageReverseIndex = null; this.pageBuilder = pageBuilder; } /** * SetupReverseIndex - exact replica of Go's SetupReverseIndex method */ setupReverseIndex() { this.pageReverseIndex = new ContentTreeReverseIndex(async (rm) => { const add = (k, n) => { const existing = rm.get(k); if (existing && existing !== ambiguousContentNode) { rm.set(k, ambiguousContentNode); } else if (!existing) { rm.set(k, n); } }; const walker = new doctree_1.NodeShiftTreeWalker({ tree: this.treePages, lockType: doctree_1.LockType.LockTypeRead, handle: async (s, n, match) => { if (n) { const [p, found] = n.getPage(); if (!found) { return [false, null]; } if (p.pageFile && p.pageFile()) { add(p.paths().baseNameNoIdentifier(), n); } } return [false, null]; } }); try { await walker.walk(); } catch (err) { log.error(`setupReverseIndex error: ${err}`); } }); } /** * InsertResourceNode - exact replica of Go's InsertResourceNode method */ insertResourceNode(key, node) { const tree = this.treeResources; const commit = tree.lock(true); try { tree.insertIntoValuesDimension(key, node); } finally { commit(); } } async addFi(f) { if (f.fileInfo().isDir()) { return; } const ps = (0, pagesource_1.newPageSource)(f); const key = ps.paths().base(); // Access bundleType from the file's getBundleType method const bundleType = ps.file.getBundleType(); switch (bundleType) { case type_1.PathType.File: this.insertResourceNode(key, (0, pagetrees_1.newPageTreesNode)(ps)); break; case type_1.PathType.ContentResource: const p = await this.pageBuilder.withSource(ps).build(); if (!p) { // Disabled page. return; } this.insertResourceNode(key, (0, pagetrees_1.newPageTreesNode)(p)); break; default: const page = await this.pageBuilder.withSource(ps).build(); this.treePages.insertWithLock(ps.paths().base(), (0, pagetrees_1.newPageTreesNode)(page)); break; } } /** * Assemble - exact replica of Go's Assemble method */ async assemble() { await this.assembleStructurePages(); await this.applyAggregates(); await this.cleanPages(); await this.assembleTerms(); } /** * AssembleTerms - exact replica of Go's assembleTerms method */ async assembleTerms() { await this.pageBuilder.term.assemble(this.treePages, this.treeTaxonomyEntries, this.pageBuilder); } /** * CleanPages - exact replica of Go's cleanPages method */ async cleanPages() { // TODO: clean all the draft, expired, scheduled in the future pages } /** * ApplyAggregates - exact replica of Go's applyAggregates method */ async applyAggregates() { // TODO // Apply cascade Aggregates to pages // Apply Dates to home, section, and meta changed pages // Apply cascade to source page // Use linked list to connect all the cascade in the same path // Restore all the changed pages in the cache } /** * AssembleStructurePages - exact replica of Go's assembleStructurePages method */ async assembleStructurePages() { await this.addMissingTaxonomies(); for (const idx of this.pageBuilder.langSvc.languageIndexes()) { const tree = this.treePages.shape(0, idx); await this.pageBuilder.section.assemble(tree, this.pageBuilder, idx); } await this.addMissingStandalone(); } /** * AddMissingTaxonomies - exact replica of Go's addMissingTaxonomies method */ async addMissingTaxonomies() { const tree = this.treePages; const commit = tree.lock(true); try { await this.pageBuilder.taxonomy.assemble(tree, this.pageBuilder); } finally { commit(); } } /** * AddMissingStandalone - exact replica of Go's addMissingStandalone method */ async addMissingStandalone() { const tree = this.treePages; const commit = tree.lock(true); try { await this.pageBuilder.standalone.assemble(tree, this.pageBuilder); } finally { commit(); } } /** * GetResourcesForPage - exact replica of Go's getResourcesForPage method */ async getResourcesForPage(ps) { const res = []; await this.forEachResourceInPage(ps, doctree_1.LockType.LockTypeNone, false, (resourceKey, n, match) => { const [rs, found] = n.getResource(); if (found) { res.push(rs); } return [false, null]; }); return res; } /** * ForEachResourceInPage - exact replica of Go's forEachResourceInPage method */ async forEachResourceInPage(ps, lockType, exact, handle) { let keyPage = ps.paths().base(); if (keyPage === "/") { keyPage = ""; } const prefix = addTrailingSlash(keyPage); const isBranch = ps.kind() !== "page"; const rw = new doctree_1.NodeShiftTreeWalker({ tree: this.treeResources.shape(0, ps.pageIdentity().pageLanguageIndex()), prefix: prefix, lockType: lockType, exact: exact, handle: async (resourceKey, n, match) => { if (isBranch) { const [ownerKey] = this.treePages.longestPrefixAll(resourceKey); if (ownerKey !== keyPage && this.pathDir(ownerKey) !== this.pathDir(resourceKey)) { // Stop walking downwards, someone else owns this resource. rw.skipPrefix(ownerKey + "/"); return [false, null]; } } return handle(resourceKey, n, match); } }); try { await rw.walk(); } catch (err) { log.error(`forEachResourceInPage error: ${err}`); } } /** * GetPagesInSection - exact replica of Go's getPagesInSection method */ async getPagesInSection(langIndex, q) { const cacheKey = q.key(); const tree = this.treePages.shape(0, langIndex); // Simplified cache implementation - in real implementation would use proper cache return this.getOrCreatePagesFromCacheSync(null, cacheKey, async (key) => { const prefix = addTrailingSlash(q.path); const pas = []; let otherBranch = ""; const include = q.include; const walker = new doctree_1.NodeShiftTreeWalker({ tree: tree, prefix: prefix, handle: async (key, n, match) => { if (q.recursive) { const [p, found] = n.getPage(); if (found && include(p)) { pas.push(p); } return [false, null]; } const [p, found] = n.getPage(); if (found && include(p)) { pas.push(p); } if (!p.isPage || !p.isPage()) { const currentBranch = key + "/"; if (otherBranch === "" || otherBranch !== currentBranch) { walker.skipPrefix(currentBranch); } otherBranch = currentBranch; } return [false, null]; } }); try { await walker.walk(); if (q.includeSelf) { const n = tree.get(q.path); if (n) { const [p, found] = n.getPage(); if (found && include(p)) { pas.push(p); } } } // Convert to Pages with len method const pages = pas; pages.len = () => pas.length; (0, sort_1.sortByWeight)(pages); return Promise.resolve(pages); } catch (err) { log.error(`getPagesInSection error: ${err}`); } // Convert to Pages with len method const pages = pas; pages.len = () => pas.length; return Promise.resolve(pages); }); } /** * GetOrCreatePagesFromCache - simplified synchronous version */ async getOrCreatePagesFromCacheSync(cache, key, create) { // Faster than cache implementation for this example return await create(key); } /** * GetPagesWithTerm - exact replica of Go's getPagesWithTerm method */ async getPagesWithTerm(q) { const key = q.key(); // Simplified cache implementation return await this.getOrCreatePagesFromCacheSync(null, key, async (cacheKey) => { const pas = []; const include = q.include; try { await this.treeTaxonomyEntries.walkPrefix(doctree_1.LockType.LockTypeNone, addTrailingSlash(q.path), (s, n) => { const [p, found] = n.getPage(); if (found && include(p)) { pas.push(p); } return [false, null]; }); // Convert to Pages with len method const pages = pas; pages.len = () => pas.length; (0, sort_1.sortByDefault)(pages); return pages; } catch (err) { log.error(`getPagesWithTerm error: ${err}`); } // Convert to Pages with len method const pages = pas; pages.len = () => pas.length; return pages; }); } /** * GetTermsForPageInTaxonomy - exact replica of Go's getTermsForPageInTaxonomy method */ getTermsForPageInTaxonomy(base, taxonomy) { const prefix = addLeadingSlash(taxonomy); return this.getOrCreatePagesFromCacheSync(null, prefix + base, async (cacheKey) => { const pas = []; try { await this.treeTaxonomyEntries.walkPrefix(doctree_1.LockType.LockTypeNone, addTrailingSlash(prefix), (s, n) => { if (s.endsWith(base)) { pas.push(n.term.page); } return [false, null]; }); // Convert to Pages with len method const pages = pas; pages.len = () => pas.length; (0, sort_1.sortByDefault)(pages); return pages; } catch (err) { log.error(`getTermsForPageInTaxonomy error: ${err}`); } // Convert to Pages with len method const pages = pas; pages.len = () => pas.length; return pages; }); } /** * GetSections - exact replica of Go's getSections method */ async getSections(langIndex, prefix) { const pagesList = []; let currentBranchPrefix = ""; const tree = this.treePages.shape(0, langIndex); const walker = new doctree_1.NodeShiftTreeWalker({ tree: tree, prefix: prefix, handle: async (ss, n, match) => { const [p, found] = n.getPage(); if (!found) { return [false, null]; } if (p.isPage && p.isPage()) { return [false, null]; } if (currentBranchPrefix === "" || !ss.startsWith(currentBranchPrefix)) { if (p.isSection && p.isSection() && p.shouldList && p.shouldList(false) && p.parent && p.parent() === p) { pagesList.push(p); } else { walker.skipPrefix(ss + "/"); } } currentBranchPrefix = ss + "/"; return [false, null]; } }); try { await walker.walk(); // Convert to Pages with len method const pages = pagesList; pages.len = () => pagesList.length; (0, sort_1.sortByDefault)(pages); return pages; } catch (err) { log.error(`getSections error: ${err}`); } // Convert to Pages with len method const pages = pagesList; pages.len = () => pagesList.length; return pages; } /** * Helper method to get directory from path */ pathDir(path) { const lastSlash = path.lastIndexOf('/'); if (lastSlash === -1) { return ''; } return path.substring(0, lastSlash); } } exports.PageMap = PageMap; //# sourceMappingURL=pagemap.js.map