diff --git a/.eslintignore b/.eslintignore index 2a08ed4a38..c09782a280 100644 --- a/.eslintignore +++ b/.eslintignore @@ -26,7 +26,6 @@ packages/core/src/variables/*.js packages/core/test/unit/**/*.js # TODO: remove when migrated to TS -!packages/core/src/Layout/*.js !markdown-it-icons.test.js !Site.test.js diff --git a/.gitignore b/.gitignore index 109122454e..fe84e40f0f 100644 --- a/.gitignore +++ b/.gitignore @@ -91,7 +91,6 @@ packages/core/src/variables/*.js packages/core/test/unit/**/*.js # TODO: remove when migrated to TS -!packages/core/src/Layout/*.js !markdown-it-icons.test.js !Site.test.js diff --git a/packages/core/src/Layout/Layout.js b/packages/core/src/Layout/Layout.ts similarity index 66% rename from packages/core/src/Layout/Layout.js rename to packages/core/src/Layout/Layout.ts index 04bc82db6c..7a63e14b29 100644 --- a/packages/core/src/Layout/Layout.js +++ b/packages/core/src/Layout/Layout.ts @@ -1,14 +1,34 @@ -const { v4: uuidv4 } = require('uuid'); +import { v4 as uuidv4 } from 'uuid'; +import { PageSources } from '../Page/PageSources'; +import { NodeProcessor } from '../html/NodeProcessor'; +import * as logger from '../utils/logger'; +import { ExternalManager, ExternalManagerConfig } from '../External/ExternalManager'; -const { PageSources } = require('../Page/PageSources'); -const { NodeProcessor } = require('../html/NodeProcessor'); +const LAYOUT_PAGE_BODY_VARIABLE = 'content'; -const logger = require('../utils/logger'); +export type LayoutConfig = ExternalManagerConfig & { externalManager: ExternalManager }; -const LAYOUT_PAGE_BODY_VARIABLE = 'content'; +export type PageNjkAssets = { + headTop: string[]; + headBottom: string[]; + scriptBottom: string[]; + layoutUserScriptsAndStyles: string[]; +}; -class Layout { - constructor(sourceFilePath, config) { +export class Layout { + sourceFilePath: string; + config: LayoutConfig; + includedFiles: Set; + layoutProcessed: string; + layoutPageBodyVariable: string; + layoutPageNavUuid: string; + headTop: string[]; + headBottom: string[]; + scriptBottom: string[]; + layoutUserScriptsAndStyles: string[]; + generatePromise: Promise | undefined; + + constructor(sourceFilePath: string, config: LayoutConfig) { this.sourceFilePath = sourceFilePath; this.config = config; @@ -24,15 +44,15 @@ class Layout { this.generatePromise = undefined; } - shouldRegenerate(filePaths) { + shouldRegenerate(filePaths: string[]): boolean { return filePaths.some(filePath => this.includedFiles.has(filePath)); } - async generate() { + async generate(): Promise { let triesLeft = 10; let numBodyVars; - let pageSources; - let nodeProcessor; + let pageSources: PageSources; + let nodeProcessor: NodeProcessor; do { const fileConfig = { @@ -51,8 +71,8 @@ class Layout { pluginManager, siteLinkManager, this.layoutUserScriptsAndStyles, 'layout'); // eslint-disable-next-line no-await-in-loop - this.layoutProcessed = await nodeProcessor.process(this.sourceFilePath, nunjucksProcessed, - this.sourceFilePath, layoutVariables); + this.layoutProcessed = await nodeProcessor.process(this.sourceFilePath, nunjucksProcessed.toString(), + this.sourceFilePath, layoutVariables) as string; this.layoutPageNavUuid = nodeProcessor.pageNavProcessor.getUuid(); this.layoutProcessed = pluginManager.postRender(nodeProcessor.frontmatter, this.layoutProcessed); @@ -75,20 +95,21 @@ class Layout { this.scriptBottom = nodeProcessor.scriptBottom; pageSources.addAllToSet(this.includedFiles); - await this.config.externalManager.generateDependencies(pageSources.getDynamicIncludeSrc(), - this.includedFiles); + await this.config.externalManager.generateDependencies( + pageSources.getDynamicIncludeSrc(), + this.includedFiles, + this.layoutUserScriptsAndStyles); } - insertPage(pageContent, pageNav, pageIncludedFiles) { + insertPage(pageContent: string, pageNav: string, pageIncludedFiles: Set): string { this.includedFiles.forEach(filePath => pageIncludedFiles.add(filePath)); - // Use function for .replace, in case string contains special patterns (e.g. $$, $&, $1, ...) return this.layoutProcessed .replace(this.layoutPageBodyVariable, () => pageContent) .replace(this.layoutPageNavUuid, () => pageNav); } - getPageNjkAssets() { + getPageNjkAssets(): PageNjkAssets { return { headTop: this.headTop, headBottom: this.headBottom, @@ -97,7 +118,3 @@ class Layout { }; } } - -module.exports = { - Layout, -}; diff --git a/packages/core/src/Layout/LayoutManager.js b/packages/core/src/Layout/LayoutManager.ts similarity index 64% rename from packages/core/src/Layout/LayoutManager.js rename to packages/core/src/Layout/LayoutManager.ts index 677543bce2..3b7da9c636 100644 --- a/packages/core/src/Layout/LayoutManager.js +++ b/packages/core/src/Layout/LayoutManager.ts @@ -1,32 +1,32 @@ -const fs = require('fs-extra'); -const path = require('path'); - -const { Layout } = require('./Layout'); - -const logger = require('../utils/logger'); +import fs from 'fs-extra'; +import path from 'path'; +import { Layout, LayoutConfig, PageNjkAssets } from './Layout'; +import * as logger from '../utils/logger'; const FRONTMATTER_NONE_ATTR = 'none'; -class LayoutManager { - constructor(config) { - this.config = config; +export class LayoutManager { + private config: LayoutConfig; + private layoutsRootPath: string; + private layouts: { [name: string]: Layout }; + constructor(config: LayoutConfig) { + this.config = config; this.layoutsRootPath = path.join(config.rootPath, '_markbind', 'layouts'); - this.layouts = {}; } /** * Flag all layouts for (re)generation when requested */ - removeLayouts() { + removeLayouts(): void { this.layouts = {}; } /** * Update layouts which have the provided filePaths as dependencies */ - updateLayouts(filePaths) { + updateLayouts(filePaths: string[]): Promise { const layoutsToRegenerate = Object.entries(this.layouts) .filter(([, layout]) => layout.shouldRegenerate(filePaths)); @@ -36,7 +36,7 @@ class LayoutManager { })); } - generateLayoutIfNeeded(name) { + generateLayoutIfNeeded(name: string): Promise | undefined { if (this.layouts[name]) { return this.layouts[name].generatePromise; } @@ -52,15 +52,18 @@ class LayoutManager { return this.layouts[name].generatePromise; } - layoutHasPageNav(name) { + layoutHasPageNav(name: string): boolean { if (name === FRONTMATTER_NONE_ATTR) { return false; } - return this.layouts[name] && this.layouts[name].layoutPageNavUuid; + return !!this.layouts[name] && !!this.layouts[name].layoutPageNavUuid; } - combineLayoutWithPage(name, pageContent, pageNav, pageIncludedFiles) { + combineLayoutWithPage(name: string, + pageContent: string, + pageNav: string, + pageIncludedFiles: Set): string { if (name === FRONTMATTER_NONE_ATTR) { return pageContent; } @@ -72,7 +75,7 @@ class LayoutManager { return this.layouts[name].insertPage(pageContent, pageNav, pageIncludedFiles); } - getLayoutPageNjkAssets(name) { + getLayoutPageNjkAssets(name: string): PageNjkAssets | {} { if (name === FRONTMATTER_NONE_ATTR || !this.layouts[name]) { return {}; } @@ -80,7 +83,3 @@ class LayoutManager { return this.layouts[name].getPageNjkAssets(); } } - -module.exports = { - LayoutManager, -}; diff --git a/packages/core/src/Layout/index.js b/packages/core/src/Layout/index.js deleted file mode 100644 index 93b7d82878..0000000000 --- a/packages/core/src/Layout/index.js +++ /dev/null @@ -1,9 +0,0 @@ -const { Layout } = require('./Layout'); -const { LayoutManager } = require('./LayoutManager'); - -module.exports = { - Layout, - LayoutManager, - LAYOUT_DEFAULT_NAME: 'default.md', - LAYOUT_FOLDER_PATH: '_markbind/layouts', -}; diff --git a/packages/core/src/Layout/index.ts b/packages/core/src/Layout/index.ts new file mode 100644 index 0000000000..3da415ae93 --- /dev/null +++ b/packages/core/src/Layout/index.ts @@ -0,0 +1,10 @@ +import { Layout } from './Layout'; +import { LayoutManager } from './LayoutManager'; + +export const LAYOUT_DEFAULT_NAME = 'default.md'; +export const LAYOUT_FOLDER_PATH = '_markbind/layouts'; + +export { + Layout, + LayoutManager, +}; diff --git a/packages/core/src/Page/PageConfig.ts b/packages/core/src/Page/PageConfig.ts index 46894c9a9e..b8a11613cf 100644 --- a/packages/core/src/Page/PageConfig.ts +++ b/packages/core/src/Page/PageConfig.ts @@ -3,6 +3,7 @@ import type { SiteLinkManager } from '../html/SiteLinkManager'; import type { PluginManager } from '../plugins/PluginManager'; import { VariableProcessor } from '../variables/VariableProcessor'; +import { LayoutManager } from '../Layout'; export interface PageAssets { bootstrap: string; @@ -66,7 +67,7 @@ export class PageConfig { template: Template; variableProcessor: VariableProcessor; addressablePagesSource: string[]; - layoutManager: any; + layoutManager: LayoutManager; constructor(args: { asset: PageAssets; diff --git a/packages/core/src/Page/index.ts b/packages/core/src/Page/index.ts index bca627d137..23fbf35b74 100644 --- a/packages/core/src/Page/index.ts +++ b/packages/core/src/Page/index.ts @@ -19,6 +19,8 @@ import type { FrontMatter } from '../plugins/Plugin'; import type { ExternalManager } from '../External/ExternalManager'; import { MbNode } from '../utils/node'; +import { LAYOUT_DEFAULT_NAME } from '../Layout'; + require('../patches/htmlparser2'); const _ = { cloneDeep, isObject, isArray }; @@ -27,10 +29,6 @@ const LockManager = require('../utils/LockManager'); const PACKAGE_VERSION = require('../../package.json').version; -const { - LAYOUT_DEFAULT_NAME, -} = require('../Layout'); - const TITLE_PREFIX_SEPARATOR = ' - '; const TITLE_SUFFIX_SEPARATOR = ' - '; @@ -475,7 +473,7 @@ export class Page { */ buildPageNav(content: string) { const isFmPageNavSpecifierValid = this.isPageNavigationSpecifierValid(); - const doesLayoutHavePageNav = this.pageConfig.layoutManager.layoutHasPageNav(this.layout); + const doesLayoutHavePageNav = this.pageConfig.layoutManager.layoutHasPageNav(this.layout!); if (isFmPageNavSpecifierValid && doesLayoutHavePageNav) { this.navigableHeadings = {}; @@ -535,12 +533,12 @@ export class Page { pluginManager.collectPluginPageNjkAssets(this.frontmatter, content, this.asset); - await layoutManager.generateLayoutIfNeeded(this.layout); + await layoutManager.generateLayoutIfNeeded(this.layout!); const pageNav = this.buildPageNav(content); - content = layoutManager.combineLayoutWithPage(this.layout, content, pageNav, this.includedFiles); + content = layoutManager.combineLayoutWithPage(this.layout!, content, pageNav, this.includedFiles); this.asset = { ...this.asset, - ...layoutManager.getLayoutPageNjkAssets(this.layout), + ...layoutManager.getLayoutPageNjkAssets(this.layout!), }; pageSources.addAllToSet(this.includedFiles); diff --git a/packages/core/src/Site/index.ts b/packages/core/src/Site/index.ts index 5609d16ce7..3b36f615fc 100644 --- a/packages/core/src/Site/index.ts +++ b/packages/core/src/Site/index.ts @@ -13,7 +13,7 @@ import { Page } from '../Page'; import { PageConfig } from '../Page/PageConfig'; import { VariableProcessor } from '../variables/VariableProcessor'; import { VariableRenderer } from '../variables/VariableRenderer'; -import { ExternalManager, ExternalManagerConfig } from '../External/ExternalManager'; +import { ExternalManager } from '../External/ExternalManager'; import { SiteLinkManager } from '../html/SiteLinkManager'; import { PluginManager } from '../plugins/PluginManager'; import type { FrontMatter } from '../plugins/Plugin'; @@ -23,10 +23,11 @@ import * as fsUtil from '../utils/fsUtil'; import * as gitUtil from '../utils/git'; import * as logger from '../utils/logger'; import { SITE_CONFIG_NAME, LAZY_LOADING_SITE_FILE_NAME, _ } from './constants'; +import { LayoutManager } from '../Layout'; +import { LayoutConfig } from '../Layout/Layout'; // Change when they are migrated to TypeScript const ProgressBar = require('../lib/progress'); -const { LayoutManager } = require('../Layout'); require('../patches/htmlparser2'); const url = { @@ -155,8 +156,7 @@ export class Site { currentOpenedPages: string[]; toRebuild: Set; externalManager!: ExternalManager; - // TODO: add LayoutManager when it has been migrated - layoutManager: any; + layoutManager!: LayoutManager; constructor(rootPath: string, outputPath: string, onePagePath: string, forceReload = false, siteConfigPath = SITE_CONFIG_NAME, dev: any, backgroundBuildMode: boolean, @@ -422,7 +422,7 @@ export class Site { * Set up the managers used with the configurations. */ buildManagers() { - const config: ExternalManagerConfig & { externalManager: ExternalManager } = { + const config: LayoutConfig = { baseUrlMap: this.baseUrlMap, baseUrl: this.siteConfig.baseUrl, rootPath: this.rootPath, @@ -618,7 +618,7 @@ export class Site { this.beforeSiteGenerate(); try { - await this.layoutManager.updateLayouts(filePaths); + await this.layoutManager.updateLayouts(filePathArray); await this.regenerateAffectedPages(uniquePaths); await fs.remove(this.tempPath); if (this.backgroundBuildMode) { diff --git a/packages/core/src/Site/template.ts b/packages/core/src/Site/template.ts index 0d2bb6a2cc..58b299dfec 100644 --- a/packages/core/src/Site/template.ts +++ b/packages/core/src/Site/template.ts @@ -7,7 +7,7 @@ import { SiteConfig, SiteConfigPage } from './SiteConfig'; import { VariableRenderer } from '../variables/VariableRenderer'; import * as logger from '../utils/logger'; -const { LAYOUT_DEFAULT_NAME, LAYOUT_FOLDER_PATH } = require('../Layout'); +import { LAYOUT_DEFAULT_NAME, LAYOUT_FOLDER_PATH } from '../Layout'; const requiredFiles = ['index.md', 'site.json', '_markbind/'];