@mdfriday/foundry
Version:
The core engine of MDFriday. Convert Markdown and shortcodes into fully themed static sites – Hugo-style, powered by TypeScript.
461 lines • 14.9 kB
JavaScript
"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.Site = void 0;
const page_1 = require("./page");
const log_1 = require("../../../../pkg/log");
const taxonomies_builder_1 = require("../../../domain/site/entity/taxonomies-builder");
// Create domain-specific logger for site operations
const log = (0, log_1.getDomainLogger)('site', { component: 'site' });
/**
* Site - TypeScript equivalent of Go's Site entity
* Main site management class
*/
class Site {
// Public properties for template access (following Go's pattern)
get Title() {
return this.title;
}
// Add Pages property for template access (equivalent to Go's Pages() method)
async Pages() {
const langIndex = this.languageSvc.getLanguageIndex(this.language.getCurrentLanguage());
const cps = await this.contentSvc.globalPages(langIndex);
return this.sitePages(cps);
}
// Add RegularPages property for template access (equivalent to Go's RegularPages() method)
get RegularPages() {
const cps = this.contentSvc.globalRegularPages();
return this.sitePages(cps);
}
constructor(configSvc, contentSvc, translationSvc, languageSvc, sitemap, staticCopySvc, publisher, author, compiler, url, ref, language, navigation, title) {
this.template = null;
this.home = null;
this.configSvc = configSvc;
this.contentSvc = contentSvc;
this.translationSvc = translationSvc;
this.languageSvc = languageSvc;
this.sitemap = sitemap;
this.staticCopySvc = staticCopySvc;
this.publisher = publisher;
this.author = author;
this.compiler = compiler;
this.url = url;
this.ref = ref;
this.language = language;
this.navigation = navigation;
this.title = title;
}
/**
* Build site
* TypeScript equivalent of Build method from Go
*/
async build(template) {
try {
this.template = template;
// Setup phase
await this.setup();
// Pre-generate menus for all languages (before rendering pages)
await this.generateNavigations();
// Copy static files as part of the build process
await this.copyStaticFiles();
// Render phase
await this.render();
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
log.error(`❌ Site build failed: ${message}`);
throw error;
}
}
/**
* Build site with progress callbacks
* TypeScript equivalent of Build method from Go with progress tracking
*/
async buildWithProgress(template, onProgress) {
try {
this.template = template;
// Setup phase
await this.setup();
// Pre-generate menus for all languages (before rendering pages)
await this.generateNavigations();
// Copy static files as part of the build process
await this.copyStaticFiles();
// Render phase with progress tracking
await this.renderWithProgress(onProgress);
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
log.error(`❌ Site build failed: ${message}`);
throw error;
}
}
/**
* Setup site before rendering
* TypeScript equivalent of setup method from Go
*/
async setup() {
try {
const languageKeys = this.languageSvc.languageKeys();
for (const lang of languageKeys) {
this.language.setCurrentLanguage(lang);
}
}
catch (error) {
const message = error instanceof Error ? error.message : String(error);
log.error(`❌ Setup failed: ${message}`);
throw error;
}
}
/**
* Render all pages
* TypeScript equivalent of render method from Go
*/
async render() {
try {
await this.renderPages();
}
catch (error) {
throw error;
}
}
/**
* Render all pages with progress tracking
* TypeScript equivalent of render method from Go with progress callbacks
*/
async renderWithProgress(onProgress) {
try {
await this.renderPagesWithProgress(onProgress);
}
catch (error) {
throw error;
}
}
/**
* Render pages for current language
* TypeScript equivalent of renderPages method from Go
* 支持增量构建:根据环境变量判断是否只渲染 stale 页面
*/
async renderPages() {
const langIndex = this.languageSvc.getLanguageIndex(this.language.getCurrentLanguage());
const pages = [];
let pageCount = 0;
await this.contentSvc.walkPages(langIndex, async (page) => {
const sitePage = await this.sitePage(page);
pages.push(sitePage);
pageCount++;
const sources = await this.contentSvc.getPageSources(page);
await sitePage.processResources(sources);
// Check if this is the home page
if (page.isHome()) {
this.home = sitePage;
}
});
for (let i = 0; i < pages.length; i++) {
const page = pages[i];
if (page.isStale()) {
await page.render();
page.clearStale();
}
}
}
/**
* Render pages for current language with progress tracking
* TypeScript equivalent of renderPages method from Go with progress callbacks
*/
async renderPagesWithProgress(onProgress) {
const langIndex = this.languageSvc.getLanguageIndex(this.language.getCurrentLanguage());
const pages = [];
let pageCount = 0;
// First pass: collect all pages
await this.contentSvc.walkPages(langIndex, async (page) => {
const sitePage = await this.sitePage(page);
pages.push(sitePage);
pageCount++;
const sources = await this.contentSvc.getPageSources(page);
await sitePage.processResources(sources);
// Check if this is the home page
if (page.isHome()) {
this.home = sitePage;
}
});
// Second pass: render pages with progress tracking
const totalPages = pages.length;
for (let i = 0; i < pages.length; i++) {
const page = pages[i];
await page.render();
// Report progress
onProgress?.({
currentPage: i + 1,
totalPages: totalPages
});
}
}
/**
* Get page output (simplified implementation)
* TypeScript equivalent of pageOutput method from Go
*/
async pageOutput(page) {
// Simplified implementation - return the page's output
return page.output();
}
/**
* Clear site cache (simplified implementation)
*/
clearSiteCache() {
// Placeholder for cache clearing logic
}
get Home() {
return this.home;
}
get Params() {
return this.configSvc.configParams();
}
get Taxonomies() {
return this.navigation.getTaxonomies(this.language.getCurrentLanguage()) || new taxonomies_builder_1.TaxonomyList();
}
get Menus() {
return this.navigation.getMenus(this.language.getCurrentLanguage());
}
getTitle() {
return this.title;
}
setTitle(title) {
this.title = title;
}
/**
* Get configuration service
*/
getConfigService() {
return this.configSvc;
}
/**
* Get content service
*/
getContentService() {
return this.contentSvc;
}
/**
* Get language service
*/
getLanguageService() {
return this.languageSvc;
}
/**
* Get base URL
* Provides the base URL service without exposing internal URL object
*/
baseURL() {
return this.url.base;
}
/**
* Get URL handler
*/
getURL() {
return this.url;
}
/**
* Get reference handler
*/
getRef() {
return this.ref;
}
/**
* Get language handler
*/
getLanguage() {
return this.language;
}
get Language() {
return this.getLanguage();
}
/**
* Get navigation handler
*/
getNavigation() {
return this.navigation;
}
/**
* Get publisher
*/
getPublisher() {
return this.publisher;
}
/**
* Get template
*/
getTemplate() {
return this.template;
}
/**
* Get author info
*/
getAuthor() {
return this.author;
}
/**
* Get compiler info
*/
getCompiler() {
return this.compiler;
}
/**
* Get sitemap service
*/
getSitemap() {
return this.sitemap;
}
/**
* Check if site is multi-language
*/
isMultipleLanguage() {
return this.language.isMultipleLanguage();
}
/**
* Get current language
*/
getCurrentLanguage() {
return this.language.lang();
}
/**
* Get language prefix for URLs
*/
languagePrefix() {
return this.language.languagePrefix();
}
/**
* Site page factory method - convert content page to site page
*/
async sitePage(target) {
return new page_1.Page(this.template, this.languageSvc, this.publisher, target, this);
}
/**
* Convert array of content pages to array of site pages
* TypeScript equivalent of Go's sitePages method
*/
sitePages(contentPages) {
const pages = [];
for (let i = 0; i < contentPages.length; i++) {
const cp = contentPages[i];
try {
// Use synchronous version to match property getter pattern
const sitePage = this.sitePageSync(cp);
pages.push(sitePage);
}
catch (error) {
log.error(`❌ [Site.sitePages] Failed to convert page ${i}:`, error);
// Skip pages that can't be converted, following Go's pattern
}
}
return pages;
}
/**
* Create site page from content page (synchronous version)
* TypeScript equivalent of Go's site page creation
*/
sitePageSync(contentPage) {
return new page_1.Page(this.template, this.languageSvc, this.publisher, contentPage, this);
}
/**
* Pre-generate menus for all languages
* This ensures menus are cached before page rendering begins
*/
async generateNavigations() {
const languageKeys = this.languageSvc.languageKeys();
for (const lang of languageKeys) {
const langIndex = this.languageSvc.getLanguageIndex(lang);
await this.navigation.generateMenusForLanguage(lang, langIndex);
await this.navigation.generateTaxonomiesForLanguage(lang, langIndex, this);
}
}
/**
* Get page by path
* TypeScript equivalent of Go's GetPage method
* Made synchronous to match template function requirements
*/
GetPage(...ref) {
if (ref.length > 1) {
throw new Error(`too many arguments to .Site.GetPage: ${ref}. Use lookups on the form {{ .Site.GetPage "/posts/mypage-md" }}`);
}
let key = ref[0];
// Normalize path separators (equivalent to filepath.ToSlash)
key = key.replace(/\\/g, '/');
// Ensure path starts with "/"
if (!key.startsWith('/')) {
key = '/' + key;
}
try {
const langIndex = this.languageSvc.getLanguageIndex(this.language.getCurrentLanguage());
// Make synchronous call to content service
const contentPage = this.contentSvc.getPageFromPathSync(langIndex, key);
if (!contentPage) {
log.warn(`⚠️ GetPage: No page found for key "${key}"`);
return null;
}
// Create site page synchronously
return this.sitePageSync(contentPage);
}
catch (error) {
log.error(`❌ Error getting page "${key}": ${error}`);
return null;
}
}
/**
* Copy static files to publish directory
* This is a core business capability of the Site entity
*/
async copyStaticFiles() {
try {
await this.staticCopySvc.copyStaticFiles(this.staticCopySvc.staticFs(), this.staticCopySvc.publishFs());
}
catch (error) {
log.error('❌ Static file copy failed:', error);
throw error;
}
}
/**
* Create site weighted page from ordinal weight page
* TypeScript equivalent of Go's siteWeightedPage method
*/
async siteWeightedPage(ordinalWeightPage) {
// First create the site page from the content page
const sitePage = await this.sitePage(ordinalWeightPage.page());
// Import WeightedPage here to avoid circular dependency
const { WeightedPage } = await Promise.resolve().then(() => __importStar(require('./taxonomies-builder')));
// Return wrapped site page with ordinal weight page
return new WeightedPage(sitePage, ordinalWeightPage);
}
}
exports.Site = Site;
//# sourceMappingURL=site.js.map