feat: react router config generation for docs

This commit is contained in:
endiliey 2018-08-08 00:39:17 +08:00
parent f9bc0ff7b8
commit 9e7729ad74
5 changed files with 124 additions and 103 deletions

View file

@ -1,47 +0,0 @@
const fs = require('fs-extra');
const path = require('path');
const fm = require('front-matter');
const globby = require('globby');
const indexRE = /(^|.*\/)index\.md$/i;
const mdRE = /\.md$/;
function fileToPath(file) {
if (indexRE.test(file)) {
return file.replace(indexRE, '/$1');
}
return `/${file.replace(mdRE, '').replace(/\\/g, '/')}`;
}
function parse(fileString) {
if (!fm.test(fileString)) {
return {metadata: null, content: fileString};
}
const {attributes: metadata, body: content} = fm(fileString);
return {metadata, content};
}
async function loadBlog(blogDir) {
const blogFiles = await globby(['**/*.md'], {
cwd: blogDir
});
const blogDatas = await Promise.all(
blogFiles.map(async file => {
const filepath = path.resolve(blogDir, file);
const fileString = await fs.readFile(filepath, 'utf-8');
const {metadata, content} = parse(fileString);
return {
path: fileToPath(file),
content,
...metadata
};
})
);
blogDatas.sort((a, b) => b.date - a.date);
return blogDatas;
}
module.exports = loadBlog;

View file

@ -2,16 +2,7 @@ const fs = require('fs-extra');
const path = require('path');
const fm = require('front-matter');
const globby = require('globby');
const indexRE = /(^|.*\/)index\.md$/i;
const mdRE = /\.md$/;
function fileToPath(file) {
if (indexRE.test(file)) {
return file.replace(indexRE, '/$1');
}
return `/${file.replace(mdRE, '').replace(/\\/g, '/')}`;
}
const {encodePath, fileToPath} = require('./utils');
function parse(fileString) {
if (!fm.test(fileString)) {
@ -22,27 +13,25 @@ function parse(fileString) {
return {metadata, content};
}
// still TODO. still copy paste from blog logic
async function loadDocs(siteDir) {
const blogFiles = await globby(['**/*.md'], {
cwd: siteDir
async function loadDocs(docsDir) {
const docsFiles = await globby(['**/*.md'], {
cwd: docsDir
});
const blogDatas = await Promise.all(
blogFiles.map(async file => {
const filepath = path.resolve(siteDir, file);
const docsData = await Promise.all(
docsFiles.map(async source => {
const filepath = path.resolve(docsDir, source);
const fileString = await fs.readFile(filepath, 'utf-8');
const {metadata, content} = parse(fileString);
const {metadata} = parse(fileString);
return {
path: fileToPath(file),
content,
path: encodePath(fileToPath(source)),
source,
...metadata
};
})
);
blogDatas.sort((a, b) => b.date - a.date);
return blogDatas;
return docsData;
}
module.exports = loadDocs;

View file

@ -1,58 +1,51 @@
const fs = require('fs-extra');
const path = require('path');
const loadConfig = require('./config');
const loadBlog = require('./blog');
const loadDocs = require('./docs');
const {generate} = require('../helpers');
const {generate} = require('./utils');
const genRoutesConfig = require('./routes');
module.exports = async function load(siteDir) {
// load siteConfig
// siteConfig
const siteConfig = loadConfig(siteDir);
// docs
const docsRelativeDir = siteConfig.customDocsPath || 'docs';
const docsMetadata = await loadDocs(
path.resolve(siteDir, '..', docsRelativeDir)
const docsDir = path.resolve(
siteDir,
'..',
siteConfig.customDocsPath || 'docs'
);
const docsData = await loadDocs(docsDir);
await generate(
'docsMetadata.js',
`${'/**\n * @generated\n */\n' + 'module.exports = '}${JSON.stringify(
docsMetadata,
null,
2
)};\n`
);
// blog
const blogMetadata = await loadBlog(path.resolve(siteDir, 'blog'));
await generate(
'blogMetadata.js',
`${'/**\n * @generated\n */\n' + 'module.exports = '}${JSON.stringify(
blogMetadata,
null,
2
)};\n`
'docsData.js',
`export const docsData = ${JSON.stringify(docsData, null, 2)}`
);
// resolve outDir
const outDir = siteConfig.dest
? path.resolve(siteConfig.dest)
: path.resolve(siteDir, '.munseo/dist');
const outDir = path.resolve(siteDir, 'build');
// resolve the path of our app user interface layout
const uiPath =
!siteConfig.uiPath ||
!fs.existsSync(path.resolve(siteDir, siteConfig.uiPath))
? path.resolve(__dirname, '../ui')
: siteConfig.uiPath;
// resolve the theme
const themePath =
siteConfig.themePath &&
fs.existsSync(path.resolve(siteDir, siteConfig.themePath))
? siteConfig.themePath
: path.resolve(__dirname, '../theme');
const baseUrl = siteConfig.baseUrl || '/';
return {
const props = {
siteConfig,
siteDir,
docsDir,
docsData,
outDir,
uiPath,
themePath,
baseUrl
};
// Generate React Router Config
const routesConfig = await genRoutesConfig(props);
await generate('routes.js', routesConfig);
return props;
};

38
lib/load/routes.js Normal file
View file

@ -0,0 +1,38 @@
const path = require('path');
const {fileToComponentName} = require('./utils');
async function genRoutesConfig({docsData, docsDir}) {
function genDocsRoute({path: docsPath, source}) {
const componentName = fileToComponentName(source);
return `
{
path: ${JSON.stringify(docsPath)},
component: () => <Docs><${componentName} /></Docs>
}`;
}
function genDocsImport({source}) {
const filePath = path.resolve(docsDir, source);
const componentName = fileToComponentName(source);
return `import ${componentName} from ${JSON.stringify(filePath)}`;
}
const notFoundRoute = `,
{
path: '*',
component: NotFound
}`;
return (
`import React from 'react';\n` +
`import Docs from '@theme/Docs';\n` +
`import NotFound from '@theme/NotFound';\n` +
`${docsData.map(genDocsImport).join('\n')}\n` +
`const routes = [${docsData
.map(genDocsRoute)
.join(',')}${notFoundRoute}\n];\n` +
`export default routes;\n`
);
}
module.exports = genRoutesConfig;

48
lib/load/utils.js Normal file
View file

@ -0,0 +1,48 @@
const path = require('path');
const fs = require('fs-extra');
const genPath = path.resolve(__dirname, '../core/generated');
fs.ensureDirSync(genPath);
const genCache = new Map();
async function generate(file, content) {
const cached = genCache.get(file);
if (cached !== content) {
await fs.writeFile(path.join(genPath, file), content);
genCache.set(file, content);
}
}
const indexRE = /(^|.*\/)index\.md$/i;
const mdRE = /\.md$/;
function fileToPath(file) {
if (indexRE.test(file)) {
return file.replace(indexRE, '/$1');
}
return `/${file.replace(mdRE, '').replace(/\\/g, '/')}`;
}
function encodePath(userpath) {
return userpath
.split('/')
.map(item => encodeURIComponent(item))
.join('/');
}
function fileToComponentName(file) {
let str = file.replace(/([A-Z])/g, ' $1');
if (str.length === 1) {
return str.toUpperCase();
}
str = str.replace(/^[\W_]+|[\W_]+$/g, '').toLowerCase();
str = str.charAt(0).toUpperCase() + str.slice(1);
return str.replace(/[\W_]+(\w|$)/g, (_, ch) => ch.toUpperCase());
}
module.exports = {
encodePath,
generate,
fileToPath,
fileToComponentName
};