From 835798d771105f18eac545b6f0b3741a0557639f Mon Sep 17 00:00:00 2001 From: tlylt Date: Mon, 17 Jul 2023 20:47:26 +0800 Subject: [PATCH] Revert typescript migration for Site/index --- packages/cli/src/cmd/build.js | 2 +- packages/cli/src/cmd/deploy.js | 2 +- packages/cli/src/cmd/init.js | 2 +- packages/cli/src/cmd/serve.js | 2 +- packages/core/src/Site/index.js | 454 +++++++++++---------------- packages/core/test/unit/Site.test.js | 2 +- 6 files changed, 190 insertions(+), 274 deletions(-) diff --git a/packages/cli/src/cmd/build.js b/packages/cli/src/cmd/build.js index 6c73ac863d..3f6f54bde9 100755 --- a/packages/cli/src/cmd/build.js +++ b/packages/cli/src/cmd/build.js @@ -1,6 +1,6 @@ const path = require('path'); -const { Site } = require('@markbind/core').Site; +const { Site } = require('@markbind/core'); const cliUtil = require('../util/cliUtil'); const logger = require('../util/logger'); diff --git a/packages/cli/src/cmd/deploy.js b/packages/cli/src/cmd/deploy.js index 475fed36cf..f38c79ade9 100755 --- a/packages/cli/src/cmd/deploy.js +++ b/packages/cli/src/cmd/deploy.js @@ -1,6 +1,6 @@ const path = require('path'); -const { Site } = require('@markbind/core').Site; +const { Site } = require('@markbind/core'); const cliUtil = require('../util/cliUtil'); const logger = require('../util/logger'); diff --git a/packages/cli/src/cmd/init.js b/packages/cli/src/cmd/init.js index 068f62ee69..95379f50ac 100755 --- a/packages/cli/src/cmd/init.js +++ b/packages/cli/src/cmd/init.js @@ -2,7 +2,7 @@ const fs = require('fs-extra'); const path = require('path'); const { Template } = require('@markbind/core'); -const { Site } = require('@markbind/core').Site; +const { Site } = require('@markbind/core'); const logger = require('../util/logger'); diff --git a/packages/cli/src/cmd/serve.js b/packages/cli/src/cmd/serve.js index cd85c89773..7243730327 100755 --- a/packages/cli/src/cmd/serve.js +++ b/packages/cli/src/cmd/serve.js @@ -1,7 +1,7 @@ const chokidar = require('chokidar'); const path = require('path'); -const { Site } = require('@markbind/core').Site; +const { Site } = require('@markbind/core'); const { pageVueServerRenderer } = require('@markbind/core/src/Page/PageVueServerRenderer'); const fsUtil = require('@markbind/core/src/utils/fsUtil'); diff --git a/packages/core/src/Site/index.js b/packages/core/src/Site/index.js index f4c767f025..4ed8ba84f4 100644 --- a/packages/core/src/Site/index.js +++ b/packages/core/src/Site/index.js @@ -1,65 +1,47 @@ -import cheerio from 'cheerio'; -import fs from 'fs-extra'; -import ignore, { Ignore } from 'ignore'; -import path from 'path'; -import walkSync from 'walk-sync'; -import simpleGit, { SimpleGit } from 'simple-git'; -import Bluebird from 'bluebird'; -import ghpages from 'gh-pages'; -import difference from 'lodash/difference'; -import differenceWith from 'lodash/differenceWith'; -import flatMap from 'lodash/flatMap'; -import has from 'lodash/has'; -import isBoolean from 'lodash/isBoolean'; -import isEmpty from 'lodash/isEmpty'; -import isEqual from 'lodash/isEqual'; -import isUndefined from 'lodash/isUndefined'; -import noop from 'lodash/noop'; -import omitBy from 'lodash/omitBy'; -import startCase from 'lodash/startCase'; -import union from 'lodash/union'; -import uniq from 'lodash/uniq'; - -import { Template as NunjucksTemplate } from 'nunjucks'; -import { SiteConfig, SiteConfigPage, SiteConfigStyle } from './SiteConfig'; -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 { SiteLinkManager } from '../html/SiteLinkManager'; -import { PluginManager } from '../plugins/PluginManager'; -import type { FrontMatter } from '../plugins/Plugin'; -import { sequentialAsyncForEach } from '../utils/async'; -import { delay } from '../utils/delay'; -import * as fsUtil from '../utils/fsUtil'; -import * as gitUtil from '../utils/git'; -import * as logger from '../utils/logger'; -import { SITE_CONFIG_NAME, INDEX_MARKDOWN_FILE, LAZY_LOADING_SITE_FILE_NAME } from './constants'; - -require('../patches/htmlparser2'); +const cheerio = require('cheerio'); require('../patches/htmlparser2'); +const fs = require('fs-extra'); +const ghpages = require('gh-pages'); +const ignore = require('ignore'); +const path = require('path'); +const Promise = require('bluebird'); +const walkSync = require('walk-sync'); +const simpleGit = require('simple-git'); const ProgressBar = require('../lib/progress'); -const { LAYOUT_FOLDER_PATH, LAYOUT_DEFAULT_NAME, LayoutManager } = require('../Layout'); - -const _ = { - difference, - differenceWith, - flatMap, - has, - isUndefined, - isEqual, - isEmpty, - isBoolean, - noop, - omitBy, - startCase, - union, - uniq, -}; -const url = { - join: path.posix.join, -}; +const { SiteConfig } = require('./SiteConfig'); +const { Page } = require('../Page'); +const { PageConfig } = require('../Page/PageConfig'); +const { VariableProcessor } = require('../variables/VariableProcessor'); +const { VariableRenderer } = require('../variables/VariableRenderer'); +const { ExternalManager } = require('../External/ExternalManager'); +const { LayoutManager, LAYOUT_DEFAULT_NAME, LAYOUT_FOLDER_PATH } = require('../Layout'); +const { SiteLinkManager } = require('../html/SiteLinkManager'); +const { PluginManager } = require('../plugins/PluginManager'); + +const { sequentialAsyncForEach } = require('../utils/async'); +const { delay } = require('../utils/delay'); +const fsUtil = require('../utils/fsUtil'); +const gitUtil = require('../utils/git'); +const logger = require('../utils/logger'); +const { SITE_CONFIG_NAME, INDEX_MARKDOWN_FILE, LAZY_LOADING_SITE_FILE_NAME } = require('./constants'); + +const _ = {}; +_.difference = require('lodash/difference'); +_.differenceWith = require('lodash/differenceWith'); +_.flatMap = require('lodash/flatMap'); +_.has = require('lodash/has'); +_.isBoolean = require('lodash/isBoolean'); +_.isEmpty = require('lodash/isEmpty'); +_.isEqual = require('lodash/isEqual'); +_.isUndefined = require('lodash/isUndefined'); +_.noop = require('lodash/noop'); +_.omitBy = require('lodash/omitBy'); +_.startCase = require('lodash/startCase'); +_.union = require('lodash/union'); +_.uniq = require('lodash/uniq'); + +const url = {}; +url.join = path.posix.join; const MARKBIND_VERSION = require('../../package.json').version; @@ -84,11 +66,11 @@ const MAX_CONCURRENT_PAGE_GENERATION_PROMISES = 4; const LAZY_LOADING_BUILD_TIME_RECOMMENDATION_LIMIT = 30000; const LAZY_LOADING_REBUILD_TIME_RECOMMENDATION_LIMIT = 5000; -function getBootswatchThemePath(theme: string) { +function getBootswatchThemePath(theme) { return require.resolve(`bootswatch/dist/${theme}/bootstrap.min.css`); } -const SUPPORTED_THEMES_PATHS: Record = { +const SUPPORTED_THEMES_PATHS = { 'bootswatch-cerulean': getBootswatchThemePath('cerulean'), 'bootswatch-cosmo': getBootswatchThemePath('cosmo'), 'bootswatch-flatly': getBootswatchThemePath('flatly'), @@ -119,85 +101,9 @@ const ABOUT_MARKDOWN_DEFAULT = '# About\n' const MARKBIND_WEBSITE_URL = 'https://markbind.org/'; const MARKBIND_LINK_HTML = `MarkBind ${MARKBIND_VERSION}`; -/* - * A page configuration object. - */ -type PageCreationConfig = { - externalScripts: string[], - frontmatter: FrontMatter, - layout: string, - pageSrc: string, - searchable: boolean, - faviconUrl?: string, - glob?: string, - globExclude?: string - title?: string, -}; - -type AddressablePage = { - frontmatter: FrontMatter, - layout: string, - searchable: string, - src: string, - externalScripts?: string[], - faviconUrl?: string, - title?: string, -}; - -type PageGenerationTask = { - mode: string, - pages: Page[] -}; - -type PageGenerationContext = { - startTime: Date, - numPagesGenerated: number, - numPagesToGenerate: number, - isCompleted: boolean, -}; - -type DeployOptions = { - branch: string, - message: string, - repo: string, - remote: string, - user?: { name: string; email: string; }, -}; - -export class Site { - dev: boolean; - rootPath: string; - outputPath: string; - tempPath: string; - siteAssetsDestPath: string; - pageTemplatePath: string; - pageTemplate: NunjucksTemplate; - pages: Page[]; - addressablePages: AddressablePage[]; - addressablePagesSource: string[]; - baseUrlMap: Set; - forceReload: boolean; - siteConfig!: SiteConfig; - siteConfigPath: string; - variableProcessor!: VariableProcessor; - layoutManager: any; // TODO: add LayoutManager when it has been migrated - pluginManager!: PluginManager; - siteLinkManager!: SiteLinkManager; - backgroundBuildMode: string | boolean; - stopGenerationTimeThreshold: Date; - postBackgroundBuildFunc: () => void; - onePagePath: string; - currentPageViewed: string; - currentOpenedPages: string[]; - toRebuild: Set; - externalManager!: ExternalManager; - buildAsset?: (this: any, arg: unknown) => Bluebird; - rebuildAffectedSourceFiles?: (this: any, arg: unknown) => Bluebird; - rebuildSourceFiles?: (this: any, arg: unknown) => Bluebird; - - constructor(rootPath: string, outputPath: string, onePagePath: string, forceReload = false, - siteConfigPath = SITE_CONFIG_NAME, dev: any, backgroundBuildMode: boolean, - postBackgroundBuildFunc: () => void) { +class Site { + constructor(rootPath, outputPath, onePagePath, forceReload = false, + siteConfigPath = SITE_CONFIG_NAME, dev, backgroundBuildMode, postBackgroundBuildFunc) { this.dev = !!dev; this.rootPath = rootPath; @@ -218,8 +124,24 @@ export class Site { this.baseUrlMap = new Set(); this.forceReload = forceReload; + /** + * @type {undefined | SiteConfig} + */ + this.siteConfig = undefined; this.siteConfigPath = siteConfigPath; + // Site wide variable processor + this.variableProcessor = undefined; + + // Site wide layout manager + this.layoutManager = undefined; + + // Site wide plugin manager + this.pluginManager = undefined; + + // Site wide link checker + this.siteLinkManager = undefined; + // Background build properties this.backgroundBuildMode = onePagePath && backgroundBuildMode; this.stopGenerationTimeThreshold = new Date(); @@ -238,12 +160,12 @@ export class Site { * Util Methods */ - static async rejectHandler(error: unknown, removeFolders: string[]) { + static async rejectHandler(error, removeFolders) { logger.warn(error); try { await Promise.all(removeFolders.map(folder => fs.remove(folder))); } catch (err) { - logger.error(`Failed to remove generated files after error!\n${(err as Error).message}`); + logger.error(`Failed to remove generated files after error!\n${err.message}`); } } @@ -258,7 +180,7 @@ export class Site { * @param normalizedUrl BaseUrl-less and extension-less url of the page * @return Boolean of whether the page needed to be rebuilt */ - changeCurrentPage(normalizedUrl: string) { + changeCurrentPage(normalizedUrl) { this.currentPageViewed = path.join(this.rootPath, normalizedUrl); if (this.toRebuild.has(this.currentPageViewed)) { @@ -277,10 +199,10 @@ export class Site { /** * Changes the list of current opened pages - * @param normalizedUrls Collection of normalized url of pages taken from the clients + * @param {Array} normalizedUrls Collection of normalized url of pages taken from the clients * ordered from most-to-least recently opened */ - changeCurrentOpenedPages(normalizedUrls: string[]) { + changeCurrentOpenedPages(normalizedUrls) { if (!this.onePagePath) { return; } @@ -302,8 +224,9 @@ export class Site { * Read and store the site config from site.json, overwrite the default base URL * if it's specified by the user. * @param baseUrl user defined base URL (if exists) + * @returns {Promise} */ - async readSiteConfig(baseUrl?: string): Promise { + async readSiteConfig(baseUrl) { try { const siteConfigPath = path.join(this.rootPath, this.siteConfigPath); const siteConfigJson = fs.readJsonSync(siteConfigPath); @@ -312,19 +235,33 @@ export class Site { return this.siteConfig; } catch (err) { throw (new Error(`Failed to read the site config file '${this.siteConfigPath}' at` - + `${this.rootPath}:\n${(err as Error).message}\nPlease ensure the file exist or is valid`)); + + `${this.rootPath}:\n${err.message}\nPlease ensure the file exist or is valid`)); } } - listAssets(fileIgnore: Ignore) { + listAssets(fileIgnore) { const files = walkSync(this.rootPath, { directories: false }); return fileIgnore.filter(files); } + /** + * A page configuration object. + * @typedef {Object} PageCreationConfig + * @property {string} faviconUrl + * @property {string} pageSrc + * @property {string} title + * @property {string} layout + * @property {Object} frontmatter + * @property {boolean} searchable + * @property {Array} externalScripts + * / + /** * Create a Page object from the site and page creation config. + * @param {PageCreationConfig} config + * @returns {Page} */ - createPage(config: PageCreationConfig): Page { + createPage(config) { const sourcePath = path.join(this.rootPath, config.pageSrc); const resultPath = path.join(this.outputPath, fsUtil.setExtension(config.pageSrc, '.html')); @@ -485,8 +422,8 @@ export class Site { /** * Helper function for addDefaultLayoutToSiteConfig(). */ - static async writeToSiteConfig(config: SiteConfig, configPath: string) { - const layoutObj: SiteConfigPage = { glob: '**/*.md', layout: LAYOUT_DEFAULT_NAME }; + static async writeToSiteConfig(config, configPath) { + const layoutObj = { glob: '**/*.md', layout: LAYOUT_DEFAULT_NAME }; config.pages.push(layoutObj); await fs.outputJson(configPath, config); } @@ -509,11 +446,10 @@ export class Site { .map(filePath => fsUtil.setExtension(filePath, '.html')); } - getPageGlobPaths(page: SiteConfigPage, pagesExclude: string[]) { - const pageGlobs = page.glob ?? []; + getPageGlobPaths(page, pagesExclude) { return walkSync(this.rootPath, { directories: false, - globs: Array.isArray(pageGlobs) ? pageGlobs : [pageGlobs], + globs: Array.isArray(page.glob) ? page.glob : [page.glob], ignore: [ CONFIG_FOLDER_NAME, SITE_FOLDER_NAME, @@ -529,7 +465,7 @@ export class Site { const { pages, pagesExclude } = this.siteConfig; const pagesFromSrc = _.flatMap(pages.filter(page => page.src), page => (Array.isArray(page.src) ? page.src.map(pageSrc => ({ ...page, src: pageSrc })) - : [page])) as unknown as AddressablePage[]; + : [page])); const set = new Set(); const duplicatePages = pagesFromSrc .filter(page => set.size === set.add(page.src).size) @@ -544,15 +480,15 @@ export class Site { searchable: page.searchable, layout: page.layout, frontmatter: page.frontmatter, - }))) as AddressablePage[]; + }))); /* Add pages collected from globs and merge properties for pages Page properties collected from src have priority over page properties from globs, while page properties from later entries take priority over earlier ones. */ - const filteredPages: Record = {}; + const filteredPages = {}; pagesFromGlobs.concat(pagesFromSrc).forEach((page) => { - const filteredPage = _.omitBy(page, _.isUndefined) as AddressablePage; + const filteredPage = _.omitBy(page, _.isUndefined); filteredPages[page.src] = page.src in filteredPages ? { ...filteredPages[page.src], ...filteredPage } : filteredPage; @@ -566,6 +502,7 @@ export class Site { /** * Collects the base url map in the site/subsites + * @returns {*} */ collectBaseUrl() { const candidates = walkSync(this.rootPath, { directories: false }) @@ -582,7 +519,7 @@ export class Site { * Set up the managers used with the configurations. */ buildManagers() { - const config: ExternalManagerConfig & { externalManager: ExternalManager } = { + const config = { baseUrlMap: this.baseUrlMap, baseUrl: this.siteConfig.baseUrl, rootPath: this.rootPath, @@ -593,10 +530,6 @@ export class Site { intrasiteLinkValidation: this.siteConfig.intrasiteLinkValidation, codeLineNumbers: this.siteConfig.style.codeLineNumbers, plantumlCheck: this.siteConfig.plantumlCheck, - headerIdMap: {}, - siteLinkManager: this.siteLinkManager, - pluginManager: this.pluginManager, - externalManager: this.externalManager, }; this.siteLinkManager = new SiteLinkManager(config); config.siteLinkManager = this.siteLinkManager; @@ -623,7 +556,7 @@ export class Site { content = fs.readFileSync(userDefinedVariablesPath, 'utf8'); } catch (e) { content = ''; - logger.warn((e as Error).message); + logger.warn(e.message); } /* @@ -638,7 +571,7 @@ export class Site { this.variableProcessor.addUserDefinedVariable(base, 'MarkBind', MARKBIND_LINK_HTML); const $ = cheerio.load(content, { decodeEntities: false }); - $('variable,span').each((_index, element) => { + $('variable,span').each((index, element) => { const name = $(element).attr('name') || $(element).attr('id'); this.variableProcessor.renderAndAddUserDefinedVariable(base, name, $(element).html()); @@ -651,7 +584,7 @@ export class Site { * if there is a change in the variables file * @param filePaths array of paths corresponding to files that have changed */ - collectUserDefinedVariablesMapIfNeeded(filePaths: string[]) { + collectUserDefinedVariablesMapIfNeeded(filePaths) { const variablesPath = path.resolve(this.rootPath, USER_VARIABLES_PATH); if (filePaths.includes(variablesPath)) { this.collectUserDefinedVariablesMap(); @@ -663,8 +596,9 @@ export class Site { /** * Generate the website. * @param baseUrl user defined base URL (if exists) + * @returns {Promise} */ - async generate(baseUrl: string | undefined): Promise { + async generate(baseUrl) { const startTime = new Date(); // Create the .tmp folder for storing intermediate results. fs.emptydirSync(this.tempPath); @@ -677,7 +611,7 @@ export class Site { try { await this.readSiteConfig(baseUrl); this.collectAddressablePages(); - this.collectBaseUrl(); + await this.collectBaseUrl(); this.collectUserDefinedVariablesMap(); await this.buildAssets(); await (this.onePagePath ? this.lazyBuildSourceFiles() : this.buildSourceFiles()); @@ -699,9 +633,9 @@ export class Site { /** * Helper function for generate(). */ - calculateBuildTimeForGenerate(startTime: Date, lazyWebsiteGenerationString: string) { + calculateBuildTimeForGenerate(startTime, lazyWebsiteGenerationString) { const endTime = new Date(); - const totalBuildTime = (endTime.getTime() - startTime.getTime()) / 1000; + const totalBuildTime = (endTime - startTime) / 1000; logger.info(`Website generation ${lazyWebsiteGenerationString}complete! Total build time: ${ totalBuildTime}s`); @@ -730,7 +664,7 @@ export class Site { /** * Adds all pages except the viewed pages to toRebuild, flagging them for lazy building later. */ - async lazyBuildAllPagesNotViewed(viewedPages: string | string[]) { + async lazyBuildAllPagesNotViewed(viewedPages) { const viewedPagesArray = Array.isArray(viewedPages) ? viewedPages : [viewedPages]; this.pages.forEach((page) => { const normalizedUrl = fsUtil.removeExtension(page.pageConfig.sourcePath); @@ -768,7 +702,7 @@ export class Site { return fs.copy(lazyLoadingSpinnerHtmlFilePath, outputSpinnerHtmlFilePath); } - async _rebuildAffectedSourceFiles(filePaths: string | string[]) { + async _rebuildAffectedSourceFiles(filePaths) { if (this.backgroundBuildMode) { this.stopOngoingBuilds(); } @@ -789,7 +723,7 @@ export class Site { } } - async _rebuildPagesBeingViewed(normalizedUrls: string[]) { + async _rebuildPagesBeingViewed(normalizedUrls) { const startTime = new Date(); const normalizedUrlArray = Array.isArray(normalizedUrls) ? normalizedUrls : [normalizedUrls]; const uniqueUrls = _.uniq(normalizedUrlArray); @@ -818,9 +752,9 @@ export class Site { /** * Helper function for _rebuildPagesBeingViewed(). */ - static calculateBuildTimeForRebuildPagesBeingViewed(startTime: Date) { + static calculateBuildTimeForRebuildPagesBeingViewed(startTime) { const endTime = new Date(); - const totalBuildTime = (endTime.getTime() - startTime.getTime()) / 1000; + const totalBuildTime = (endTime - startTime) / 1000; return logger.info(`Lazy website regeneration complete! Total build time: ${totalBuildTime}s`); } @@ -839,9 +773,9 @@ export class Site { /** * Generates pages that are marked to be built/rebuilt. - * @returns A Promise that resolves once all pages are generated. + * @returns {Promise} A Promise that resolves once all pages are generated. */ - async generatePagesMarkedToRebuild(): Promise { + async generatePagesMarkedToRebuild() { const pagesToRebuild = this.pages.filter((page) => { const normalizedUrl = fsUtil.removeExtension(page.pageConfig.sourcePath); return this.toRebuild.has(normalizedUrl); @@ -892,7 +826,7 @@ export class Site { await this.buildSourceFiles(); } - async _buildMultipleAssets(filePaths: string | string[]) { + async _buildMultipleAssets(filePaths) { const filePathArray = Array.isArray(filePaths) ? filePaths : [filePaths]; const uniquePaths = _.uniq(filePathArray); const fileIgnore = ignore().add(this.siteConfig.ignore); @@ -903,7 +837,7 @@ export class Site { logger.info('Assets built'); } - async _removeMultipleAssets(filePaths: string | string[]) { + async _removeMultipleAssets(filePaths) { const filePathArray = Array.isArray(filePaths) ? filePaths : [filePaths]; const uniquePaths = _.uniq(filePathArray); const fileRelativePaths = uniquePaths.map(filePath => path.relative(this.rootPath, filePath)); @@ -953,17 +887,15 @@ export class Site { /** * Handles the rebuilding of modified pages */ - async handlePageReload(oldAddressablePages: AddressablePage[], oldPagesSrc: string[], - oldSiteConfig: SiteConfig) { + async handlePageReload(oldAddressablePages, oldPagesSrc, oldSiteConfig) { this.collectAddressablePages(); // Comparator for the _differenceWith comparison below - const isNewPage = (newPage: AddressablePage, oldPage: AddressablePage) => - _.isEqual(newPage, oldPage) || newPage.src === oldPage.src; + const isNewPage = (newPage, oldPage) => _.isEqual(newPage, oldPage) || newPage.src === oldPage.src; const addedPages = _.differenceWith(this.addressablePages, oldAddressablePages, isNewPage); const removedPages = _.differenceWith(oldAddressablePages, this.addressablePages, isNewPage) - .map(filePath => fsUtil.setExtension(filePath.src as string, '.html')); + .map(filePath => fsUtil.setExtension(filePath.src, '.html')); // Checks if any attributes of site.json requiring a global rebuild are modified const isGlobalConfigModified = () => !_.isEqual(oldSiteConfig.faviconPath, this.siteConfig.faviconPath) @@ -988,8 +920,12 @@ export class Site { await this.writeSiteData(); } else { // Get pages with edited attributes but with the same src - const editedPages = _.differenceWith(this.addressablePages, oldAddressablePages, (newPage, oldPage) => - _.isEqual(newPage, oldPage) || !oldPagesSrc.includes(newPage.src)); + const editedPages = _.differenceWith(this.addressablePages, oldAddressablePages, (newPage, oldPage) => { + if (!_.isEqual(newPage, oldPage)) { + return !oldPagesSrc.includes(newPage.src); + } + return true; + }); this.updatePages(editedPages); const siteConfigDirectory = path.dirname(path.join(this.rootPath, this.siteConfigPath)); this.regenerateAffectedPages(editedPages.map(page => path.join(siteConfigDirectory, page.src))); @@ -999,7 +935,7 @@ export class Site { /** * Creates new pages and replaces the original pages with the updated version */ - updatePages(pagesToUpdate: AddressablePage[]) { + updatePages(pagesToUpdate) { pagesToUpdate.forEach((pageToUpdate) => { this.pages.forEach((page, index) => { if (page.pageConfig.src === pageToUpdate.src) { @@ -1014,7 +950,7 @@ export class Site { /** * Handles the reloading of ignore attributes */ - async handleIgnoreReload(oldIgnore: string[]) { + async handleIgnoreReload(oldIgnore) { const assetsToRemove = _.difference(this.siteConfig.ignore, oldIgnore); if (!_.isEqual(oldIgnore, this.siteConfig.ignore)) { @@ -1027,7 +963,7 @@ export class Site { /** * Handles the reloading of the style attribute if it has been modified */ - async handleStyleReload(oldStyle: SiteConfigStyle) { + async handleStyleReload(oldStyle) { if (!_.isEqual(oldStyle.bootstrapTheme, this.siteConfig.style.bootstrapTheme)) { await this.copyBootstrapTheme(true); logger.info('Updated bootstrap theme'); @@ -1036,20 +972,20 @@ export class Site { /** * Checks if a specified file path is a dependency of a page - * @param filePath file path to check - * @returns whether the file path is a dependency of any of the site's pages + * @param {string} filePath file path to check + * @returns {boolean} whether the file path is a dependency of any of the site's pages */ - isDependencyOfPage(filePath: string): boolean { + isDependencyOfPage(filePath) { return this.pages.some(page => page.isDependency(filePath)) || fsUtil.ensurePosix(filePath).endsWith(USER_VARIABLES_PATH); } /** * Checks if a specified file path satisfies a src or glob in any of the page configurations. - * @param filePath file path to check - * @returns whether the file path is satisfies any glob + * @param {string} filePath file path to check + * @returns {boolean} whether the file path is satisfies any glob */ - isFilepathAPage(filePath: string): boolean { + isFilepathAPage(filePath) { const { pages, pagesExclude } = this.siteConfig; const relativeFilePath = fsUtil.ensurePosix(path.relative(this.rootPath, filePath)); const srcesFromPages = _.flatMap(pages.filter(page => page.src), @@ -1080,17 +1016,19 @@ export class Site { /** * Maps an array of addressable pages to an array of Page object + * @param {Array} addressablePages + * @param {String} faviconUrl */ - mapAddressablePagesToPages(addressablePages: AddressablePage[], faviconUrl: string | undefined) { + mapAddressablePagesToPages(addressablePages, faviconUrl) { this.pages = addressablePages.map(page => this.createNewPage(page, faviconUrl)); } /** * Creates and returns a new Page with the given page config details and favicon url - * @param page config - * @param faviconUrl of the page + * @param {Page} page config + * @param {String} faviconUrl of the page */ - createNewPage(page: AddressablePage, faviconUrl: string | undefined) { + createNewPage(page, faviconUrl) { return this.createPage({ faviconUrl, pageSrc: page.src, @@ -1098,7 +1036,7 @@ export class Site { layout: page.layout, frontmatter: page.frontmatter, searchable: page.searchable !== 'no', - externalScripts: page.externalScripts || [], + externalScripts: page.externalScripts, }); } @@ -1109,11 +1047,11 @@ export class Site { /** * Runs the supplied page generation tasks according to the specified mode of each task. * A page generation task can be a sequential generation or an asynchronous generation. - * @param pageGenerationTasks Array of page generation tasks - * @returns A Promise that resolves to a boolean which indicates whether the generation + * @param {Array} pageGenerationTasks Array of page generation tasks + * @returns {Promise} A Promise that resolves to a boolean which indicates whether the generation * ran to completion */ - async runPageGenerationTasks(pageGenerationTasks: PageGenerationTask[]): Promise { + async runPageGenerationTasks(pageGenerationTasks) { const pagesCount = pageGenerationTasks.reduce((acc, task) => acc + task.pages.length, 0); const progressBar = new ProgressBar(`[:bar] :current / ${pagesCount} pages built`, { total: pagesCount }); progressBar.render(); @@ -1132,7 +1070,7 @@ export class Site { if (task.mode === 'sequential') { isCompleted = await this.generatePagesSequential(task.pages, progressBar); } else { - isCompleted = await this.generatePagesAsyncThrottled(task.pages, progressBar) as boolean; + isCompleted = await this.generatePagesAsyncThrottled(task.pages, progressBar); } logger.removeProgressBar(); @@ -1144,12 +1082,12 @@ export class Site { /** * Generate pages sequentially. That is, the pages are generated * one-by-one in order. - * @param pages Pages to be generated - * @param progressBar Progress bar of the overall generation process - * @returns A Promise that resolves to a boolean which indicates whether the generation + * @param {Array} pages Pages to be generated + * @param {ProgressBar} progressBar Progress bar of the overall generation process + * @returns {Promise} A Promise that resolves to a boolean which indicates whether the generation * ran to completion */ - async generatePagesSequential(pages: Page[], progressBar: any): Promise { + async generatePagesSequential(pages, progressBar) { const startTime = new Date(); let isCompleted = true; await sequentialAsyncForEach(pages, async (page) => { @@ -1178,14 +1116,14 @@ export class Site { /** * Creates the supplied pages' page generation promises at a throttled rate. * This is done to avoid pushing too many callbacks into the event loop at once. (#1245) - * @param pages Pages to be generated - * @param progressBar Progress bar of the overall generation process - * @returns A Promise that resolves to a boolean which indicates whether the generation + * @param {Array} pages Pages to be generated + * @param {ProgressBar} progressBar Progress bar of the overall generation process + * @returns {Promise} A Promise that resolves to a boolean which indicates whether the generation * ran to completion */ - generatePagesAsyncThrottled(pages: Page[], progressBar: any): Promise { + generatePagesAsyncThrottled(pages, progressBar) { return new Promise((resolve, reject) => { - const context: PageGenerationContext = { + const context = { startTime: new Date(), numPagesGenerated: 0, numPagesToGenerate: pages.length, @@ -1231,8 +1169,7 @@ export class Site { /** * Helper function for generatePagesAsyncThrottled(). */ - generateProgressBarStatus(progressBar: any, context: PageGenerationContext, - pageGenerationQueue: (() => Promise)[], resolve: ((arg0: boolean) => any)) { + generateProgressBarStatus(progressBar, context, pageGenerationQueue, resolve) { // Post-generate guard to ensure no new callbacks are executed on stop if (this.backgroundBuildMode && context.startTime < this.stopGenerationTimeThreshold) { if (context.isCompleted) { @@ -1247,7 +1184,7 @@ export class Site { context.numPagesGenerated += 1; if (pageGenerationQueue.length) { - pageGenerationQueue.pop()!(); + pageGenerationQueue.pop()(); } else if (context.numPagesGenerated === context.numPagesToGenerate) { resolve(true); } @@ -1291,7 +1228,7 @@ export class Site { await landingPage.generate(this.externalManager); } - async regenerateAffectedPages(filePaths: string[]) { + async regenerateAffectedPages(filePaths) { const startTime = new Date(); const shouldRebuildAllPages = this.collectUserDefinedVariablesMapIfNeeded(filePaths) || this.forceReload; @@ -1300,7 +1237,7 @@ export class Site { } this._setTimestampVariable(); - let openedPagesToRegenerate: Page[] = []; + let openedPagesToRegenerate = []; const asyncPagesToRegenerate = this.pages.filter((page) => { const doFilePathsHaveSourceFiles = filePaths.some(filePath => page.isDependency(filePath)); @@ -1368,9 +1305,9 @@ export class Site { /** * Helper function for regenerateAffectedPages(). */ - calculateBuildTimeForRegenerateAffectedPages(startTime: Date) { + calculateBuildTimeForRegenerateAffectedPages(startTime) { const endTime = new Date(); - const totalBuildTime = (endTime.getTime() - startTime.getTime()) / 1000; + const totalBuildTime = (endTime - startTime) / 1000; logger.info(`Website regeneration complete! Total build time: ${totalBuildTime}s`); if (!this.onePagePath && totalBuildTime > LAZY_LOADING_REBUILD_TIME_RECOMMENDATION_LIMIT) { logger.info('Your pages took quite a while to rebuild...' @@ -1446,7 +1383,7 @@ export class Site { * Copies bootstrapTheme to the assets folder if a valid bootstrapTheme is specified * @param {Boolean} isRebuild only true if it is a rebuild */ - copyBootstrapTheme(isRebuild: boolean) { + copyBootstrapTheme(isRebuild) { const { bootstrapTheme } = this.siteConfig.style; /** @@ -1468,9 +1405,9 @@ export class Site { /** * Writes the site data to siteData.json - * @param verbose Flag to emit logs of the operation + * @param {boolean} verbose Flag to emit logs of the operation */ - async writeSiteData(verbose: boolean = true) { + async writeSiteData(verbose = true) { const siteDataPath = path.join(this.outputPath, SITE_DATA_NAME); const siteData = { enableSearch: this.siteConfig.enableSearch, @@ -1494,8 +1431,8 @@ export class Site { } } - deploy(ciTokenVar: string | boolean) { - const defaultDeployConfig: DeployOptions = { + deploy(ciTokenVar) { + const defaultDeployConfig = { branch: 'gh-pages', message: 'Site Update.', repo: '', @@ -1508,8 +1445,8 @@ export class Site { /** * Helper function for deploy(). Returns the ghpages link where the repo will be hosted. */ - async generateDepUrl(ciTokenVar: boolean | string, defaultDeployConfig: DeployOptions) { - const publish = Bluebird.promisify(ghpages.publish); + async generateDepUrl(ciTokenVar, defaultDeployConfig) { + const publish = Promise.promisify(ghpages.publish); await this.readSiteConfig(); const depOptions = await this.getDepOptions(ciTokenVar, defaultDeployConfig, publish); return Site.getDepUrl(depOptions, defaultDeployConfig); @@ -1518,20 +1455,17 @@ export class Site { /** * Helper function for deploy(). Set the options needed to be used by ghpages.publish. */ - async getDepOptions(ciTokenVar: boolean | string, defaultDeployConfig: DeployOptions, - publish: (basePath: string, options: DeployOptions) => Bluebird) { + async getDepOptions(ciTokenVar, defaultDeployConfig, publish) { const basePath = this.siteConfig.deploy.baseDir || this.outputPath; if (!fs.existsSync(basePath)) { throw new Error( 'The site directory does not exist. Please build the site first before deploy.'); } - const options: DeployOptions = { - branch: this.siteConfig.deploy.branch || defaultDeployConfig.branch, - message: this.siteConfig.deploy.message || defaultDeployConfig.message, - repo: this.siteConfig.deploy.repo || defaultDeployConfig.repo, - remote: '', - }; + const options = {}; + options.branch = this.siteConfig.deploy.branch || defaultDeployConfig.branch; + options.message = this.siteConfig.deploy.message || defaultDeployConfig.message; options.message = options.message.concat(' [skip ci]'); + options.repo = this.siteConfig.deploy.repo || defaultDeployConfig.repo; if (ciTokenVar) { const ciToken = _.isBoolean(ciTokenVar) ? 'GITHUB_TOKEN' : ciTokenVar; @@ -1587,7 +1521,7 @@ export class Site { /** * Extract repo slug from user-specified repo URL so that we can include the access token */ - static extractRepoSlug(repo: string, ciRepoSlug: string | undefined) { + static extractRepoSlug(repo, ciRepoSlug) { if (!repo) { return ciRepoSlug; } @@ -1604,7 +1538,7 @@ export class Site { /** * Helper function for deploy(). */ - static getDepUrl(options: DeployOptions, defaultDeployConfig: DeployOptions) { + static getDepUrl(options, defaultDeployConfig) { const git = simpleGit({ baseDir: process.cwd() }); options.remote = defaultDeployConfig.remote; return Site.getDeploymentUrl(git, options); @@ -1613,13 +1547,13 @@ export class Site { /** * Gets the deployed website's url, returning null if there was an error retrieving it. */ - static async getDeploymentUrl(git: SimpleGit, options: DeployOptions) { + static async getDeploymentUrl(git, options) { const HTTPS_PREAMBLE = 'https://'; const SSH_PREAMBLE = 'git@github.com:'; const GITHUB_IO_PART = 'github.io'; // https://.github.io// - function constructGhPagesUrl(remoteUrl: string) { + function constructGhPagesUrl(remoteUrl) { if (!remoteUrl) { return null; } @@ -1646,8 +1580,8 @@ export class Site { const promises = [cnamePromise, remoteUrlPromise]; try { - const promiseResults: string[] = await Promise.all(promises) as string[]; - const generateGhPagesUrl = (results: string[]) => { + const promiseResults = await Promise.all(promises); + const generateGhPagesUrl = (results) => { const cname = results[0]; const remoteUrl = results[1]; if (cname) { @@ -1666,7 +1600,7 @@ export class Site { } _setTimestampVariable() { - const options: Intl.DateTimeFormatOptions = { + const options = { weekday: 'short', year: 'numeric', month: 'short', @@ -1677,21 +1611,6 @@ export class Site { const time = new Date().toLocaleTimeString(this.siteConfig.locale, options); this.variableProcessor.addUserDefinedVariableForAllSites('timestamp', time); } - - // eslint-disable-next-line @typescript-eslint/no-unused-vars, class-methods-use-this - async rebuildPagesBeingViewed(_currentPageViewed: string) { - throw new Error('Method not implemented.'); - } - - // eslint-disable-next-line @typescript-eslint/no-unused-vars, class-methods-use-this - async removeAsset(_removedPageFilePaths: string | string[]) { - throw new Error('Method not implemented.'); - } - - // eslint-disable-next-line @typescript-eslint/no-unused-vars, class-methods-use-this - async backgroundBuildNotViewedFiles(_arg0?: any, _arg1?: any) { - throw new Error('Method not implemented.'); - } } /** @@ -1702,34 +1621,31 @@ export class Site { * Build/copy assets that are specified in filePaths * @param filePaths a single path or an array of paths corresponding to the assets to build */ -Site.prototype.buildAsset = delay(Site.prototype._buildMultipleAssets as () => Bluebird, 1000); +Site.prototype.buildAsset = delay(Site.prototype._buildMultipleAssets, 1000); -Site.prototype.rebuildPagesBeingViewed = delay( - Site.prototype._rebuildPagesBeingViewed as () => Bluebird, 1000); +Site.prototype.rebuildPagesBeingViewed = delay(Site.prototype._rebuildPagesBeingViewed, 1000); /** * Rebuild pages that are affected by changes in filePaths * @param filePaths a single path or an array of paths corresponding to the files that have changed */ -Site.prototype.rebuildAffectedSourceFiles = delay( - Site.prototype._rebuildAffectedSourceFiles as () => Bluebird, 1000); +Site.prototype.rebuildAffectedSourceFiles = delay(Site.prototype._rebuildAffectedSourceFiles, 1000); /** * Rebuild all pages * @param filePaths a single path or an array of paths corresponding to the files that have changed */ -Site.prototype.rebuildSourceFiles = delay( - Site.prototype._rebuildSourceFiles as () => Bluebird, 1000); +Site.prototype.rebuildSourceFiles = delay(Site.prototype._rebuildSourceFiles, 1000); /** * Remove assets that are specified in filePaths * @param filePaths a single path or an array of paths corresponding to the assets to remove */ -Site.prototype.removeAsset = delay( - Site.prototype._removeMultipleAssets as () => Bluebird, 1000); +Site.prototype.removeAsset = delay(Site.prototype._removeMultipleAssets, 1000); /** * Builds pages that are yet to build/rebuild in the background */ -Site.prototype.backgroundBuildNotViewedFiles = delay( - Site.prototype._backgroundBuildNotViewedFiles as () => Bluebird, 1000); +Site.prototype.backgroundBuildNotViewedFiles = delay(Site.prototype._backgroundBuildNotViewedFiles, 1000); + +module.exports = Site; diff --git a/packages/core/test/unit/Site.test.js b/packages/core/test/unit/Site.test.js index b826679feb..d69c0462aa 100644 --- a/packages/core/test/unit/Site.test.js +++ b/packages/core/test/unit/Site.test.js @@ -1,8 +1,8 @@ const path = require('path'); const fs = require('fs-extra'); const ghpages = require('gh-pages'); +const Site = require('../../src/Site'); const { Template } = require('../../src/Site/template'); -const { Site } = require('../../src/Site'); const { INDEX_MD_DEFAULT,