Skip to content

Commit

Permalink
Move and Refactor convert to Template (#2349)
Browse files Browse the repository at this point in the history
* Move convert from Site/index.ts to template.ts

* Remove redundant code

* Move readSiteConfig to SiteConfig.ts

* Move lodash const to constants.ts

* Update readSiteConfig comments

* Rename template to templatePath

* Replace then/catch with try/catch
  • Loading branch information
WillCWX committed Sep 23, 2023
1 parent 2664920 commit 19ac4c2
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 194 deletions.
42 changes: 19 additions & 23 deletions packages/cli/src/cmd/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ const fs = require('fs-extra');
const path = require('path');

const { Template } = require('@markbind/core');
const { Site } = require('@markbind/core').Site;

const logger = require('../util/logger');

function init(root, options) {
async function init(root, options) {
const rootFolder = path.resolve(root || process.cwd());

if (options.convert) {
Expand All @@ -17,28 +16,25 @@ function init(root, options) {
}

const template = new Template(rootFolder, options.template);
template.init()
.then(() => {
logger.info('Initialization success.');
})
.then(() => {
if (options.convert) {
logger.info('Converting to MarkBind website.');
const outputRoot = path.join(rootFolder, '_site');
new Site(rootFolder, outputRoot).convert()
.then(() => {
logger.info('Conversion success.');
})
.catch((error) => {
logger.error(error.message);
process.exitCode = 1;
});
}
})
.catch((error) => {
logger.error(`Failed to initialize site with given template with error: ${error.message}`);

try {
await template.init();
logger.info('Initialization success.');
} catch (error) {
logger.error(`Failed to initialize site with given template with error: ${error.message}`);
process.exitCode = 1;
}

if (options.convert) {
logger.info('Converting to MarkBind website.');
try {
await template.convert();
logger.info('Conversion success.');
} catch (error) {
logger.error(error.message);
process.exitCode = 1;
});
}
}
}

module.exports = {
Expand Down
23 changes: 23 additions & 0 deletions packages/core/src/Site/SiteConfig.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import fs from 'fs-extra';
import path from 'path';
import { FrontMatter } from '../plugins/Plugin';

const HEADING_INDEXING_LEVEL_DEFAULT = 3;
Expand Down Expand Up @@ -99,4 +101,25 @@ export class SiteConfig {
this.plantumlCheck = siteConfigJson.plantumlCheck !== undefined
? siteConfigJson.plantumlCheck : true; // check PlantUML's prerequisite by default
}

/**
* Read and returns the site config from site.json, overwrites the default base URL
* if it's specified by the user.
*
* @param rootPath The absolute path to the site folder
* @param siteConfigPath The relative path to the siteConfig
* @param baseUrl user defined base URL (if exists)
*/
static async readSiteConfig(rootPath: string, siteConfigPath: string, baseUrl?: string): Promise<any> {
try {
const absoluteSiteConfigPath = path.join(rootPath, siteConfigPath);
const siteConfigJson = fs.readJsonSync(absoluteSiteConfigPath);
const siteConfig = new SiteConfig(siteConfigJson, baseUrl);

return siteConfig;
} catch (err) {
throw (new Error(`Failed to read the site config file '${siteConfigPath}' at`
+ `${rootPath}:\n${(err as Error).message}\nPlease ensure the file exist or is valid`));
}
}
}
29 changes: 29 additions & 0 deletions packages/core/src/Site/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,32 @@
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';

export const INDEX_MARKDOWN_FILE = 'index.md';
export const SITE_CONFIG_NAME = 'site.json';
export const LAZY_LOADING_SITE_FILE_NAME = 'LazyLiveReloadLoadingSite.html';
export const _ = {
difference,
differenceWith,
flatMap,
has,
isUndefined,
isEqual,
isEmpty,
isBoolean,
noop,
omitBy,
startCase,
union,
uniq,
};
168 changes: 5 additions & 163 deletions packages/core/src/Site/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,6 @@ 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';
Expand All @@ -35,29 +22,13 @@ 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';
import { SITE_CONFIG_NAME, LAZY_LOADING_SITE_FILE_NAME, _ } from './constants';

// Change when they are migrated to TypeScript
const ProgressBar = require('../lib/progress');
const { LayoutManager, LAYOUT_DEFAULT_NAME, LAYOUT_FOLDER_PATH } = require('../Layout');
const { LayoutManager } = require('../Layout');
require('../patches/htmlparser2');

const _ = {
difference,
differenceWith,
flatMap,
has,
isUndefined,
isEqual,
isEmpty,
isBoolean,
noop,
omitBy,
startCase,
union,
uniq,
};

const url = {
join: path.posix.join,
};
Expand All @@ -70,16 +41,12 @@ const TEMP_FOLDER_NAME = '.temp';
const TEMPLATE_SITE_ASSET_FOLDER_NAME = 'markbind';
const LAYOUT_SITE_FOLDER_NAME = 'layouts';

const ABOUT_MARKDOWN_FILE = 'about.md';
const FAVICON_DEFAULT_PATH = 'favicon.ico';
const USER_VARIABLES_PATH = '_markbind/variables.md';

const PAGE_TEMPLATE_NAME = 'page.njk';
const SITE_DATA_NAME = 'siteData.json';

const WIKI_SITE_NAV_PATH = '_Sidebar.md';
const WIKI_FOOTER_PATH = '_Footer.md';

const MAX_CONCURRENT_PAGE_GENERATION_PROMISES = 4;

const LAZY_LOADING_BUILD_TIME_RECOMMENDATION_LIMIT = 30000;
Expand Down Expand Up @@ -114,9 +81,6 @@ const HIGHLIGHT_ASSETS = {
light: 'codeblock-light.min.css',
};

const ABOUT_MARKDOWN_DEFAULT = '# About\n'
+ 'Welcome to your **About Us** page.\n';

const MARKBIND_WEBSITE_URL = 'https://markbind.org/';
const MARKBIND_LINK_HTML = `<a href='${MARKBIND_WEBSITE_URL}'>MarkBind ${MARKBIND_VERSION}</a>`;

Expand Down Expand Up @@ -301,17 +265,9 @@ export class Site {
* if it's specified by the user.
* @param baseUrl user defined base URL (if exists)
*/
async readSiteConfig(baseUrl?: string): Promise<any> {
try {
const siteConfigPath = path.join(this.rootPath, this.siteConfigPath);
const siteConfigJson = fs.readJsonSync(siteConfigPath);
this.siteConfig = new SiteConfig(siteConfigJson, baseUrl);

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`));
}
async readSiteConfig(baseUrl?: string) {
this.siteConfig = await SiteConfig.readSiteConfig(this.rootPath, this.siteConfigPath, baseUrl);
return this.siteConfig;
}

listAssets(fileIgnore: Ignore) {
Expand Down Expand Up @@ -375,120 +331,6 @@ export class Site {
return new Page(pageConfig, this.siteConfig);
}

/**
* Converts an existing GitHub wiki or docs folder to a MarkBind website.
*/
async convert() {
await this.readSiteConfig();
this.collectAddressablePages();
await this.addIndexPage();
await this.addAboutPage();
this.addDefaultLayoutFiles();
await this.addDefaultLayoutToSiteConfig();
Site.printBaseUrlMessage();
}

/**
* Copies over README.md or Home.md to default index.md if present.
*/
async addIndexPage() {
const indexPagePath = path.join(this.rootPath, INDEX_MARKDOWN_FILE);
const fileNames = ['README.md', 'Home.md'];
const filePath = fileNames.find(fileName => fs.existsSync(path.join(this.rootPath, fileName)));
// if none of the files exist, do nothing
if (_.isUndefined(filePath)) return;
try {
await fs.copy(path.join(this.rootPath, filePath), indexPagePath);
} catch (error) {
throw new Error(`Failed to copy over ${filePath}`);
}
}

/**
* Adds an about page to site if not present.
*/
async addAboutPage() {
const aboutPath = path.join(this.rootPath, ABOUT_MARKDOWN_FILE);
try {
await fs.access(aboutPath);
} catch (error) {
if (fs.existsSync(aboutPath)) {
return;
}
await fs.outputFile(aboutPath, ABOUT_MARKDOWN_DEFAULT);
}
}

/**
* Adds a footer to default layout of site.
*/
addDefaultLayoutFiles() {
const wikiFooterPath = path.join(this.rootPath, WIKI_FOOTER_PATH);
let footer;
if (fs.existsSync(wikiFooterPath)) {
logger.info(`Copied over the existing ${WIKI_FOOTER_PATH} file to the converted layout`);
footer = `\n${fs.readFileSync(wikiFooterPath, 'utf8')}`;
}

const wikiSiteNavPath = path.join(this.rootPath, WIKI_SITE_NAV_PATH);
let siteNav;
if (fs.existsSync(wikiSiteNavPath)) {
logger.info(`Copied over the existing ${WIKI_SITE_NAV_PATH} file to the converted layout\n`
+ 'Check https://markbind.org/userGuide/tweakingThePageStructure.html#site-navigation-menus\n'
+ 'for information on site navigation menus.');
siteNav = fs.readFileSync(wikiSiteNavPath, 'utf8');
} else {
siteNav = this.buildSiteNav();
}

const convertedLayoutTemplate = VariableRenderer.compile(
fs.readFileSync(path.join(__dirname, 'siteConvertLayout.njk'), 'utf8'));
const renderedLayout = convertedLayoutTemplate.render({
footer,
siteNav,
});
const layoutOutputPath = path.join(this.rootPath, LAYOUT_FOLDER_PATH, LAYOUT_DEFAULT_NAME);

fs.writeFileSync(layoutOutputPath, renderedLayout, 'utf-8');
}

/**
* Builds a site navigation file from the directory structure of the site.
*/
buildSiteNav() {
let siteNavContent = '';
this.addressablePages
.filter(addressablePage => !addressablePage.src.startsWith('_'))
.forEach((page) => {
const addressablePagePath = path.join(this.rootPath, page.src);
const relativePagePathWithoutExt = fsUtil.removeExtensionPosix(
path.relative(this.rootPath, addressablePagePath));
const pageName = _.startCase(fsUtil.removeExtension(path.basename(addressablePagePath)));
const pageUrl = `{{ baseUrl }}/${relativePagePathWithoutExt}.html`;
siteNavContent += `* [${pageName}](${pageUrl})\n`;
});

return siteNavContent.trimEnd();
}

/**
* Applies the default layout to all addressable pages by modifying the site config file.
*/
async addDefaultLayoutToSiteConfig() {
const configPath = path.join(this.rootPath, SITE_CONFIG_NAME);
const config = await fs.readJson(configPath);
await Site.writeToSiteConfig(config, configPath);
}

/**
* Helper function for addDefaultLayoutToSiteConfig().
*/
static async writeToSiteConfig(config: SiteConfig, configPath: string) {
const layoutObj: SiteConfigPage = { glob: '**/*.md', layout: LAYOUT_DEFAULT_NAME };
config.pages.push(layoutObj);
await fs.outputJson(configPath, config);
}

static printBaseUrlMessage() {
logger.info('The default base URL of your site is set to /\n'
+ 'You can change the base URL of your site by editing site.json\n'
Expand Down

0 comments on commit 19ac4c2

Please sign in to comment.