Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move and Refactor convert to Template #2349

Merged
merged 8 commits into from
Sep 23, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 13 additions & 17 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()
await template.init()
tlylt marked this conversation as resolved.
Show resolved Hide resolved
.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}`);
process.exitCode = 1;
});
if (options.convert) {
logger.info('Converting to MarkBind website.');
await template.convert()
.then(() => {
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 @@ -304,17 +268,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 @@ -378,120 +334,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
Loading