mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-11 08:07:26 +02:00
Refactor + add more tests (Part 1) (#847)
* Refactor mdToHtml out * Refactor routing + move it to server instead of core * Refactor & Add more tests for server utils * Refactor isSeparateCss function from server & generate * Refactor insertTableOfContents from server & generate + add tests * undo small nits
This commit is contained in:
parent
a7a214fb3a
commit
defcbcc8ee
14 changed files with 322 additions and 235 deletions
28
lib/core/__tests__/__fixtures__/insertTOC.md
Normal file
28
lib/core/__tests__/__fixtures__/insertTOC.md
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
---
|
||||||
|
id: pokemon-commands
|
||||||
|
title: Pokemon Commands
|
||||||
|
---
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
<AUTOGENERATED_TABLE_OF_CONTENTS>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Reference
|
||||||
|
|
||||||
|
### `pokemon-run`
|
||||||
|
|
||||||
|
Alias: `run`.
|
||||||
|
|
||||||
|
### `pokemon-fight`
|
||||||
|
|
||||||
|
Alias: `fight`
|
||||||
|
|
||||||
|
### `pokemon-bag`
|
||||||
|
|
||||||
|
Alias: `bag`
|
||||||
|
|
||||||
|
### `pokemon-rename`
|
||||||
|
|
||||||
|
Alias: `rename`
|
|
@ -1,6 +1,6 @@
|
||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`with custom heading levels 1`] = `
|
exports[`getTOC with custom heading levels 1`] = `
|
||||||
Array [
|
Array [
|
||||||
Object {
|
Object {
|
||||||
"children": Array [
|
"children": Array [
|
||||||
|
@ -105,7 +105,7 @@ Array [
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`with defaults 1`] = `
|
exports[`getTOC with defaults 1`] = `
|
||||||
Array [
|
Array [
|
||||||
Object {
|
Object {
|
||||||
"children": Array [
|
"children": Array [
|
||||||
|
@ -185,3 +185,57 @@ Array [
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`insertTOC AUTOGENERATED_TABLE_OF_CONTENTS does not exist 1`] = `
|
||||||
|
"## foo
|
||||||
|
### foo
|
||||||
|
### foo 1
|
||||||
|
## foo 1
|
||||||
|
## foo 2
|
||||||
|
### foo
|
||||||
|
#### 4th level headings
|
||||||
|
All 4th level headings should not be shown by default
|
||||||
|
|
||||||
|
## bar
|
||||||
|
### bar
|
||||||
|
#### bar
|
||||||
|
4th level heading should be ignored by default, but is should be always taken
|
||||||
|
into account, when generating slugs
|
||||||
|
### \`bar\`
|
||||||
|
#### \`bar\`
|
||||||
|
## bar
|
||||||
|
### bar
|
||||||
|
#### bar
|
||||||
|
## bar
|
||||||
|
"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`insertTOC AUTOGENERATED_TABLE_OF_CONTENTS exists 1`] = `
|
||||||
|
"
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
- [\`pokemon-run\`](#pokemon-run)
|
||||||
|
- [\`pokemon-fight\`](#pokemon-fight)
|
||||||
|
- [\`pokemon-bag\`](#pokemon-bag)
|
||||||
|
- [\`pokemon-rename\`](#pokemon-rename)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Reference
|
||||||
|
|
||||||
|
### \`pokemon-run\`
|
||||||
|
|
||||||
|
Alias: \`run\`.
|
||||||
|
|
||||||
|
### \`pokemon-fight\`
|
||||||
|
|
||||||
|
Alias: \`fight\`
|
||||||
|
|
||||||
|
### \`pokemon-bag\`
|
||||||
|
|
||||||
|
Alias: \`bag\`
|
||||||
|
|
||||||
|
### \`pokemon-rename\`
|
||||||
|
|
||||||
|
Alias: \`rename\`"
|
||||||
|
`;
|
|
@ -1,33 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2017-present, Facebook, Inc.
|
|
||||||
*
|
|
||||||
* This source code is licensed under the MIT license found in the
|
|
||||||
* LICENSE file in the root directory of this source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const path = require('path');
|
|
||||||
const readFileSync = require('fs').readFileSync;
|
|
||||||
const getTOC = require('../getTOC');
|
|
||||||
|
|
||||||
const mdContents = readFileSync(
|
|
||||||
path.join(__dirname, '__fixtures__', 'getTOC.md'),
|
|
||||||
'utf8'
|
|
||||||
);
|
|
||||||
|
|
||||||
test('with defaults', () => {
|
|
||||||
const headings = getTOC(mdContents);
|
|
||||||
const headingsJson = JSON.stringify(headings);
|
|
||||||
|
|
||||||
expect(headings).toMatchSnapshot();
|
|
||||||
expect(headingsJson).toContain('bar-8'); // maximum unique bar index is 8
|
|
||||||
expect(headingsJson).not.toContain('4th level headings');
|
|
||||||
});
|
|
||||||
|
|
||||||
test('with custom heading levels', () => {
|
|
||||||
const headings = getTOC(mdContents, 'h2', ['h3', 'h4']);
|
|
||||||
const headingsJson = JSON.stringify(headings);
|
|
||||||
|
|
||||||
expect(headings).toMatchSnapshot();
|
|
||||||
expect(headingsJson).toContain('bar-8'); // maximum unique bar index is 8
|
|
||||||
expect(headingsJson).toContain('4th level headings');
|
|
||||||
});
|
|
60
lib/core/__tests__/toc.test.js
Normal file
60
lib/core/__tests__/toc.test.js
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2017-present, Facebook, Inc.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const readFileSync = require('fs').readFileSync;
|
||||||
|
const {getTOC, insertTOC} = require('../toc');
|
||||||
|
const {extractMetadata} = require('../../server/metadataUtils');
|
||||||
|
|
||||||
|
const getTOCmd = readFileSync(
|
||||||
|
path.join(__dirname, '__fixtures__', 'getTOC.md'),
|
||||||
|
'utf8'
|
||||||
|
);
|
||||||
|
|
||||||
|
const insertTOCmd = readFileSync(
|
||||||
|
path.join(__dirname, '__fixtures__', 'insertTOC.md'),
|
||||||
|
'utf8'
|
||||||
|
);
|
||||||
|
|
||||||
|
describe('getTOC', () => {
|
||||||
|
test('with defaults', () => {
|
||||||
|
const headings = getTOC(getTOCmd);
|
||||||
|
const headingsJson = JSON.stringify(headings);
|
||||||
|
|
||||||
|
expect(headings).toMatchSnapshot();
|
||||||
|
expect(headingsJson).toContain('bar-8'); // maximum unique bar index is 8
|
||||||
|
expect(headingsJson).not.toContain('4th level headings');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('with custom heading levels', () => {
|
||||||
|
const headings = getTOC(getTOCmd, 'h2', ['h3', 'h4']);
|
||||||
|
const headingsJson = JSON.stringify(headings);
|
||||||
|
|
||||||
|
expect(headings).toMatchSnapshot();
|
||||||
|
expect(headingsJson).toContain('bar-8'); // maximum unique bar index is 8
|
||||||
|
expect(headingsJson).toContain('4th level headings');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('insertTOC', () => {
|
||||||
|
test('null or undefined content', () => {
|
||||||
|
expect(insertTOC(null)).toBeNull();
|
||||||
|
expect(insertTOC(undefined)).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('AUTOGENERATED_TABLE_OF_CONTENTS does not exist', () => {
|
||||||
|
const rawContent = extractMetadata(getTOCmd).rawContent;
|
||||||
|
expect(insertTOC(rawContent)).toMatchSnapshot();
|
||||||
|
expect(insertTOC(rawContent)).toEqual(rawContent);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('AUTOGENERATED_TABLE_OF_CONTENTS exists', () => {
|
||||||
|
const rawContent = extractMetadata(insertTOCmd).rawContent;
|
||||||
|
expect(insertTOC(rawContent)).toMatchSnapshot();
|
||||||
|
expect(insertTOC(rawContent)).not.toEqual(rawContent);
|
||||||
|
});
|
||||||
|
});
|
|
@ -8,7 +8,7 @@
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
|
|
||||||
const siteConfig = require(`${process.cwd()}/siteConfig.js`);
|
const siteConfig = require(`${process.cwd()}/siteConfig.js`);
|
||||||
const getTOC = require('../getTOC');
|
const {getTOC} = require('../toc');
|
||||||
|
|
||||||
const Link = ({hashLink, content}) => (
|
const Link = ({hashLink, content}) => (
|
||||||
<a
|
<a
|
||||||
|
|
|
@ -9,7 +9,7 @@ const Remarkable = require('remarkable');
|
||||||
const mdToc = require('markdown-toc');
|
const mdToc = require('markdown-toc');
|
||||||
const toSlug = require('./toSlug');
|
const toSlug = require('./toSlug');
|
||||||
|
|
||||||
const tagToLevel = tag => Number(tag.slice(1));
|
const TABLE_OF_CONTENTS_TOKEN = '<AUTOGENERATED_TABLE_OF_CONTENTS>';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a table of content from the headings
|
* Returns a table of content from the headings
|
||||||
|
@ -18,16 +18,15 @@ const tagToLevel = tag => Number(tag.slice(1));
|
||||||
* Array of heading objects with `hashLink`, `content` and `children` fields
|
* Array of heading objects with `hashLink`, `content` and `children` fields
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
module.exports = (content, headingTags = 'h2', subHeadingTags = 'h3') => {
|
function getTOC(content, headingTags = 'h2', subHeadingTags = 'h3') {
|
||||||
|
const tagToLevel = tag => Number(tag.slice(1));
|
||||||
const headingLevels = [].concat(headingTags).map(tagToLevel);
|
const headingLevels = [].concat(headingTags).map(tagToLevel);
|
||||||
const subHeadingLevels = subHeadingTags
|
const subHeadingLevels = subHeadingTags
|
||||||
? [].concat(subHeadingTags).map(tagToLevel)
|
? [].concat(subHeadingTags).map(tagToLevel)
|
||||||
: [];
|
: [];
|
||||||
const allowedHeadingLevels = headingLevels.concat(subHeadingLevels);
|
const allowedHeadingLevels = headingLevels.concat(subHeadingLevels);
|
||||||
|
|
||||||
const md = new Remarkable();
|
const md = new Remarkable();
|
||||||
const headings = mdToc(content).json;
|
const headings = mdToc(content).json;
|
||||||
|
|
||||||
const toc = [];
|
const toc = [];
|
||||||
const context = {};
|
const context = {};
|
||||||
let current;
|
let current;
|
||||||
|
@ -36,11 +35,9 @@ module.exports = (content, headingTags = 'h2', subHeadingTags = 'h3') => {
|
||||||
// we need always generate slugs to ensure, that we will have consistent
|
// we need always generate slugs to ensure, that we will have consistent
|
||||||
// slug indexes for headings with the same names
|
// slug indexes for headings with the same names
|
||||||
const hashLink = toSlug(heading.content, context);
|
const hashLink = toSlug(heading.content, context);
|
||||||
|
|
||||||
if (!allowedHeadingLevels.includes(heading.lvl)) {
|
if (!allowedHeadingLevels.includes(heading.lvl)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rawContent = mdToc.titleize(heading.content);
|
const rawContent = mdToc.titleize(heading.content);
|
||||||
const entry = {
|
const entry = {
|
||||||
hashLink,
|
hashLink,
|
||||||
|
@ -48,7 +45,6 @@ module.exports = (content, headingTags = 'h2', subHeadingTags = 'h3') => {
|
||||||
content: md.renderInline(rawContent),
|
content: md.renderInline(rawContent),
|
||||||
children: [],
|
children: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
if (headingLevels.includes(heading.lvl)) {
|
if (headingLevels.includes(heading.lvl)) {
|
||||||
toc.push(entry);
|
toc.push(entry);
|
||||||
current = entry;
|
current = entry;
|
||||||
|
@ -56,6 +52,25 @@ module.exports = (content, headingTags = 'h2', subHeadingTags = 'h3') => {
|
||||||
current.children.push(entry);
|
current.children.push(entry);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return toc;
|
return toc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// takes the content of a doc article and returns the content with a table of
|
||||||
|
// contents inserted
|
||||||
|
function insertTOC(rawContent) {
|
||||||
|
if (!rawContent || rawContent.indexOf(TABLE_OF_CONTENTS_TOKEN) === -1) {
|
||||||
|
return rawContent;
|
||||||
|
}
|
||||||
|
const filterRe = /^`[^`]*`/;
|
||||||
|
const headers = getTOC(rawContent, 'h3', null);
|
||||||
|
const tableOfContents = headers
|
||||||
|
.filter(header => filterRe.test(header.rawContent))
|
||||||
|
.map(header => ` - [${header.rawContent}](#${header.hashLink})`)
|
||||||
|
.join('\n');
|
||||||
|
return rawContent.replace(TABLE_OF_CONTENTS_TOKEN, tableOfContents);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getTOC,
|
||||||
|
insertTOC,
|
||||||
};
|
};
|
|
@ -30,7 +30,6 @@ function getPath(path, cleanUrl = false) {
|
||||||
? path.replace(/\/index.html$/, '')
|
? path.replace(/\/index.html$/, '')
|
||||||
: removeExtension(path);
|
: removeExtension(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,19 +5,11 @@
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const {
|
const routing = require('../routing');
|
||||||
blogRouting,
|
|
||||||
docsRouting,
|
|
||||||
dotRouting,
|
|
||||||
feedRouting,
|
|
||||||
noExtRouting,
|
|
||||||
pageRouting,
|
|
||||||
sitemapRouting,
|
|
||||||
} = require('../routing');
|
|
||||||
|
|
||||||
describe('Blog routing', () => {
|
describe('Blog routing', () => {
|
||||||
const blogRegex = blogRouting('/');
|
const blogRegex = routing.blog('/');
|
||||||
const blogRegex2 = blogRouting('/react/');
|
const blogRegex2 = routing.blog('/react/');
|
||||||
|
|
||||||
test('valid blog', () => {
|
test('valid blog', () => {
|
||||||
expect('/blog/test.html').toMatch(blogRegex);
|
expect('/blog/test.html').toMatch(blogRegex);
|
||||||
|
@ -43,8 +35,8 @@ describe('Blog routing', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Docs routing', () => {
|
describe('Docs routing', () => {
|
||||||
const docsRegex = docsRouting('/');
|
const docsRegex = routing.docs('/');
|
||||||
const docsRegex2 = docsRouting('/reason/');
|
const docsRegex2 = routing.docs('/reason/');
|
||||||
|
|
||||||
test('valid docs', () => {
|
test('valid docs', () => {
|
||||||
expect('/docs/en/test.html').toMatch(docsRegex);
|
expect('/docs/en/test.html').toMatch(docsRegex);
|
||||||
|
@ -70,7 +62,7 @@ describe('Docs routing', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Dot routing', () => {
|
describe('Dot routing', () => {
|
||||||
const dotRegex = dotRouting();
|
const dotRegex = routing.dotfiles();
|
||||||
|
|
||||||
test('valid url with dot after last slash', () => {
|
test('valid url with dot after last slash', () => {
|
||||||
expect('/docs/en/test.23').toMatch(dotRegex);
|
expect('/docs/en/test.23').toMatch(dotRegex);
|
||||||
|
@ -96,8 +88,8 @@ describe('Dot routing', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Feed routing', () => {
|
describe('Feed routing', () => {
|
||||||
const feedRegex = feedRouting('/');
|
const feedRegex = routing.feed('/');
|
||||||
const feedRegex2 = feedRouting('/reason/');
|
const feedRegex2 = routing.feed('/reason/');
|
||||||
|
|
||||||
test('valid feed url', () => {
|
test('valid feed url', () => {
|
||||||
expect('/blog/atom.xml').toMatch(feedRegex);
|
expect('/blog/atom.xml').toMatch(feedRegex);
|
||||||
|
@ -126,7 +118,7 @@ describe('Feed routing', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Extension-less url routing', () => {
|
describe('Extension-less url routing', () => {
|
||||||
const noExtRegex = noExtRouting();
|
const noExtRegex = routing.noExtension();
|
||||||
|
|
||||||
test('valid no extension url', () => {
|
test('valid no extension url', () => {
|
||||||
expect('/test').toMatch(noExtRegex);
|
expect('/test').toMatch(noExtRegex);
|
||||||
|
@ -146,8 +138,8 @@ describe('Extension-less url routing', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Page routing', () => {
|
describe('Page routing', () => {
|
||||||
const pageRegex = pageRouting('/');
|
const pageRegex = routing.page('/');
|
||||||
const pageRegex2 = pageRouting('/reason/');
|
const pageRegex2 = routing.page('/reason/');
|
||||||
|
|
||||||
test('valid page url', () => {
|
test('valid page url', () => {
|
||||||
expect('/index.html').toMatch(pageRegex);
|
expect('/index.html').toMatch(pageRegex);
|
||||||
|
@ -173,8 +165,8 @@ describe('Page routing', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Sitemap routing', () => {
|
describe('Sitemap routing', () => {
|
||||||
const sitemapRegex = sitemapRouting('/');
|
const sitemapRegex = routing.sitemap('/');
|
||||||
const sitemapRegex2 = sitemapRouting('/reason/');
|
const sitemapRegex2 = routing.sitemap('/reason/');
|
||||||
|
|
||||||
test('valid sitemap url', () => {
|
test('valid sitemap url', () => {
|
||||||
expect('/sitemap.xml').toMatch(sitemapRegex);
|
expect('/sitemap.xml').toMatch(sitemapRegex);
|
|
@ -8,6 +8,24 @@ const path = require('path');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const utils = require('../utils');
|
const utils = require('../utils');
|
||||||
|
|
||||||
|
jest.mock('../env', () => ({
|
||||||
|
translation: {
|
||||||
|
enabled: true,
|
||||||
|
enabledLanguages: () => [
|
||||||
|
{
|
||||||
|
enabled: true,
|
||||||
|
name: 'English',
|
||||||
|
tag: 'en',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enabled: true,
|
||||||
|
name: '日本語',
|
||||||
|
tag: 'ja',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
describe('server utils', () => {
|
describe('server utils', () => {
|
||||||
test('minify css', () => {
|
test('minify css', () => {
|
||||||
const testCss = fs.readFileSync(
|
const testCss = fs.readFileSync(
|
||||||
|
@ -21,4 +39,44 @@ describe('server utils', () => {
|
||||||
utils.minifyCss(testCss).then(css => expect(css).toMatchSnapshot());
|
utils.minifyCss(testCss).then(css => expect(css).toMatchSnapshot());
|
||||||
utils.minifyCss(notCss).catch(e => expect(e).toMatchSnapshot());
|
utils.minifyCss(notCss).catch(e => expect(e).toMatchSnapshot());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('getLanguage', () => {
|
||||||
|
const testDocEnglish = path.join('translated_docs', 'en', 'test.md');
|
||||||
|
const testDocJapanese = path.join('translated_docs', 'ja', 'test.md');
|
||||||
|
const testDocJapaneseInSubfolder = path.join(
|
||||||
|
'translated_docs',
|
||||||
|
'ja',
|
||||||
|
'en',
|
||||||
|
'test.md'
|
||||||
|
);
|
||||||
|
const testDocInSubfolder = path.join('docs', 'ro', 'test.md');
|
||||||
|
const testDocNoLanguage = path.join('docs', 'test.md');
|
||||||
|
expect(utils.getLanguage(testDocEnglish, 'translated_docs')).toBe('en');
|
||||||
|
expect(utils.getLanguage(testDocJapanese, 'translated_docs')).toBe('ja');
|
||||||
|
expect(
|
||||||
|
utils.getLanguage(testDocJapaneseInSubfolder, 'translated_docs')
|
||||||
|
).toBe('ja');
|
||||||
|
expect(utils.getLanguage(testDocInSubfolder, 'docs')).toBeNull();
|
||||||
|
expect(utils.getLanguage(testDocNoLanguage, 'docs')).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('getSubdir', () => {
|
||||||
|
const docA = path.join('docs', 'endiliey', 'a.md');
|
||||||
|
const docB = path.join('docs', 'nus', 'hackers', 'b.md');
|
||||||
|
const docC = path.join('docs', 'c.md');
|
||||||
|
const docD = path.join('website', 'translated_docs', 'wow', 'd.md');
|
||||||
|
const docE = path.join('website', 'translated_docs', 'lol', 'lah', 'e.md');
|
||||||
|
const docsDir = path.join('docs');
|
||||||
|
const translatedDir = path.join('website', 'translated_docs');
|
||||||
|
expect(utils.getSubDir(docA, docsDir)).toEqual('endiliey');
|
||||||
|
expect(utils.getSubDir(docA, translatedDir)).toBeNull();
|
||||||
|
expect(utils.getSubDir(docB, docsDir)).toEqual('nus/hackers');
|
||||||
|
expect(utils.getSubDir(docB, translatedDir)).toBeNull();
|
||||||
|
expect(utils.getSubDir(docC, docsDir)).toBeNull();
|
||||||
|
expect(utils.getSubDir(docC, translatedDir)).toBeNull();
|
||||||
|
expect(utils.getSubDir(docD, docsDir)).toBeNull();
|
||||||
|
expect(utils.getSubDir(docD, translatedDir)).toEqual('wow');
|
||||||
|
expect(utils.getSubDir(docE, docsDir)).toBeNull();
|
||||||
|
expect(utils.getSubDir(docE, translatedDir)).toEqual('lol/lah');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -14,9 +14,9 @@ async function execute() {
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const readMetadata = require('./readMetadata.js');
|
const readMetadata = require('./readMetadata.js');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const getTOC = require('../core/getTOC');
|
const {insertTOC} = require('../core/toc');
|
||||||
const utils = require('../core/utils.js');
|
const {getPath} = require('../core/utils.js');
|
||||||
const serverUtils = require('./utils');
|
const {minifyCss, isSeparateCss} = require('./utils');
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
const mkdirp = require('mkdirp');
|
const mkdirp = require('mkdirp');
|
||||||
const glob = require('glob');
|
const glob = require('glob');
|
||||||
|
@ -53,36 +53,6 @@ async function execute() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TABLE_OF_CONTENTS_TOKEN = '<AUTOGENERATED_TABLE_OF_CONTENTS>';
|
|
||||||
|
|
||||||
// takes the content of a doc article and returns the content with a table of
|
|
||||||
// contents inserted
|
|
||||||
const insertTableOfContents = rawContent => {
|
|
||||||
const filterRe = /^`[^`]*`/;
|
|
||||||
const headers = getTOC(rawContent, 'h3', null);
|
|
||||||
|
|
||||||
const tableOfContents = headers
|
|
||||||
.filter(header => filterRe.test(header.rawContent))
|
|
||||||
.map(header => ` - [${header.rawContent}](#${header.hashLink})`)
|
|
||||||
.join('\n');
|
|
||||||
|
|
||||||
return rawContent.replace(TABLE_OF_CONTENTS_TOKEN, tableOfContents);
|
|
||||||
};
|
|
||||||
|
|
||||||
// returns true if a file should be excluded from concatentation to
|
|
||||||
// default Docusaurus styles
|
|
||||||
function isSeparateCss(file) {
|
|
||||||
if (!siteConfig.separateCss) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (let i = 0; i < siteConfig.separateCss.length; i++) {
|
|
||||||
if (file.includes(siteConfig.separateCss[i])) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('generate.js triggered...');
|
console.log('generate.js triggered...');
|
||||||
|
|
||||||
// array of tags of enabled languages
|
// array of tags of enabled languages
|
||||||
|
@ -103,23 +73,7 @@ async function execute() {
|
||||||
|
|
||||||
const buildDir = join(CWD, 'build', siteConfig.projectName);
|
const buildDir = join(CWD, 'build', siteConfig.projectName);
|
||||||
|
|
||||||
// mdToHtml is a map from a markdown file name to its html link, used to
|
const mdToHtml = metadataUtils.mdToHtml(Metadata, siteConfig.baseUrl);
|
||||||
// change relative markdown links that work on GitHub into actual site links
|
|
||||||
const mdToHtml = {};
|
|
||||||
Object.keys(Metadata).forEach(id => {
|
|
||||||
const metadata = Metadata[id];
|
|
||||||
if (metadata.language !== 'en' || metadata.original_id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let htmlLink =
|
|
||||||
siteConfig.baseUrl + metadata.permalink.replace('/next/', '/');
|
|
||||||
if (htmlLink.includes('/docs/en/')) {
|
|
||||||
htmlLink = htmlLink.replace('/docs/en/', '/docs/en/VERSION/');
|
|
||||||
} else {
|
|
||||||
htmlLink = htmlLink.replace('/docs/', '/docs/VERSION/');
|
|
||||||
}
|
|
||||||
mdToHtml[metadata.source] = htmlLink;
|
|
||||||
});
|
|
||||||
|
|
||||||
const DocsLayout = require('../core/DocsLayout.js');
|
const DocsLayout = require('../core/DocsLayout.js');
|
||||||
const Redirect = require('../core/Redirect.js');
|
const Redirect = require('../core/Redirect.js');
|
||||||
|
@ -154,16 +108,14 @@ async function execute() {
|
||||||
const language = metadata.language;
|
const language = metadata.language;
|
||||||
|
|
||||||
// generate table of contents if appropriate
|
// generate table of contents if appropriate
|
||||||
if (rawContent && rawContent.indexOf(TABLE_OF_CONTENTS_TOKEN) !== -1) {
|
rawContent = insertTOC(rawContent);
|
||||||
rawContent = insertTableOfContents(rawContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultVersion = env.versioning.defaultVersion;
|
const defaultVersion = env.versioning.defaultVersion;
|
||||||
|
|
||||||
// replace any links to markdown files to their website html links
|
// replace any links to markdown files to their website html links
|
||||||
Object.keys(mdToHtml).forEach(key => {
|
Object.keys(mdToHtml).forEach(key => {
|
||||||
let link = mdToHtml[key];
|
let link = mdToHtml[key];
|
||||||
link = utils.getPath(link, siteConfig.cleanUrl);
|
link = getPath(link, siteConfig.cleanUrl);
|
||||||
link = link.replace('/en/', `/${language}/`);
|
link = link.replace('/en/', `/${language}/`);
|
||||||
link = link.replace(
|
link = link.replace(
|
||||||
'/VERSION/',
|
'/VERSION/',
|
||||||
|
@ -171,14 +123,9 @@ async function execute() {
|
||||||
? `/${metadata.version}/`
|
? `/${metadata.version}/`
|
||||||
: '/'
|
: '/'
|
||||||
);
|
);
|
||||||
// replace relative links without "./"
|
// replace relative links with & without "./"
|
||||||
rawContent = rawContent.replace(
|
rawContent = rawContent.replace(
|
||||||
new RegExp(`\\]\\(${key}`, 'g'),
|
new RegExp(`\\]\\((${key}|\\./${key})`, 'g'),
|
||||||
`](${link}`
|
|
||||||
);
|
|
||||||
// replace relative links with "./"
|
|
||||||
rawContent = rawContent.replace(
|
|
||||||
new RegExp(`\\]\\(\\./${key}`, 'g'),
|
|
||||||
`](${link}`
|
`](${link}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -204,10 +151,7 @@ async function execute() {
|
||||||
env.translation.enabled &&
|
env.translation.enabled &&
|
||||||
metadata.permalink.indexOf('docs/en') !== -1
|
metadata.permalink.indexOf('docs/en') !== -1
|
||||||
) {
|
) {
|
||||||
const redirectlink = utils.getPath(
|
const redirectlink = getPath(metadata.permalink, siteConfig.cleanUrl);
|
||||||
metadata.permalink,
|
|
||||||
siteConfig.cleanUrl
|
|
||||||
);
|
|
||||||
const redirectComp = (
|
const redirectComp = (
|
||||||
<Redirect
|
<Redirect
|
||||||
metadata={metadata}
|
metadata={metadata}
|
||||||
|
@ -391,7 +335,10 @@ async function execute() {
|
||||||
// Remember the nuance of glob: https://www.npmjs.com/package/glob#windows
|
// Remember the nuance of glob: https://www.npmjs.com/package/glob#windows
|
||||||
const normalizedFile = path.normalize(file);
|
const normalizedFile = path.normalize(file);
|
||||||
// parse css files to replace colors and fonts according to siteConfig
|
// parse css files to replace colors and fonts according to siteConfig
|
||||||
if (normalizedFile.match(/\.css$/) && !isSeparateCss(normalizedFile)) {
|
if (
|
||||||
|
normalizedFile.match(/\.css$/) &&
|
||||||
|
!isSeparateCss(normalizedFile, siteConfig.separateCss)
|
||||||
|
) {
|
||||||
const mainCss = join(buildDir, 'css', 'main.css');
|
const mainCss = join(buildDir, 'css', 'main.css');
|
||||||
let cssContent = fs.readFileSync(normalizedFile, 'utf8');
|
let cssContent = fs.readFileSync(normalizedFile, 'utf8');
|
||||||
cssContent = `${fs.readFileSync(mainCss, 'utf8')}\n${cssContent}`;
|
cssContent = `${fs.readFileSync(mainCss, 'utf8')}\n${cssContent}`;
|
||||||
|
@ -445,7 +392,7 @@ async function execute() {
|
||||||
// Use cssnano to minify the final combined CSS.
|
// Use cssnano to minify the final combined CSS.
|
||||||
const mainCss = join(buildDir, 'css', 'main.css');
|
const mainCss = join(buildDir, 'css', 'main.css');
|
||||||
const cssContent = fs.readFileSync(mainCss, 'utf8');
|
const cssContent = fs.readFileSync(mainCss, 'utf8');
|
||||||
const css = await serverUtils.minifyCss(cssContent);
|
const css = await minifyCss(cssContent);
|
||||||
fs.writeFileSync(mainCss, css);
|
fs.writeFileSync(mainCss, css);
|
||||||
|
|
||||||
// compile/copy pages from user
|
// compile/copy pages from user
|
||||||
|
|
|
@ -63,6 +63,27 @@ function extractMetadata(content) {
|
||||||
return {metadata, rawContent: both.content};
|
return {metadata, rawContent: both.content};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mdToHtml is a map from a markdown file name to its html link, used to
|
||||||
|
// change relative markdown links that work on GitHub into actual site links
|
||||||
|
function mdToHtml(Metadata, baseUrl) {
|
||||||
|
const result = {};
|
||||||
|
Object.keys(Metadata).forEach(id => {
|
||||||
|
const metadata = Metadata[id];
|
||||||
|
if (metadata.language !== 'en' || metadata.original_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let htmlLink = baseUrl + metadata.permalink.replace('/next/', '/');
|
||||||
|
if (htmlLink.includes('/docs/en/')) {
|
||||||
|
htmlLink = htmlLink.replace('/docs/en/', '/docs/en/VERSION/');
|
||||||
|
} else {
|
||||||
|
htmlLink = htmlLink.replace('/docs/', '/docs/VERSION/');
|
||||||
|
}
|
||||||
|
result[metadata.source] = htmlLink;
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
extractMetadata,
|
extractMetadata,
|
||||||
|
mdToHtml,
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,45 +4,43 @@
|
||||||
* This source code is licensed under the MIT license found in the
|
* This source code is licensed under the MIT license found in the
|
||||||
* LICENSE file in the root directory of this source tree.
|
* LICENSE file in the root directory of this source tree.
|
||||||
*/
|
*/
|
||||||
function blogRouting(baseUrl) {
|
function blog(baseUrl) {
|
||||||
return new RegExp(`^${baseUrl}blog/.*html$`);
|
return new RegExp(`^${baseUrl}blog/.*html$`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function docsRouting(baseUrl) {
|
function docs(baseUrl) {
|
||||||
return new RegExp(`^${baseUrl}docs/.*html$`);
|
return new RegExp(`^${baseUrl}docs/.*html$`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function dotRouting() {
|
function dotfiles() {
|
||||||
return /(?!.*html$)^\/.*\.[^\n/]+$/;
|
return /(?!.*html$)^\/.*\.[^\n/]+$/;
|
||||||
}
|
}
|
||||||
|
|
||||||
function feedRouting(baseUrl) {
|
function feed(baseUrl) {
|
||||||
return new RegExp(`^${baseUrl}blog/(feed.xml|atom.xml)$`);
|
return new RegExp(`^${baseUrl}blog/(feed.xml|atom.xml)$`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function noExtRouting() {
|
function noExtension() {
|
||||||
return /\/[^.]*\/?$/;
|
return /\/[^.]*\/?$/;
|
||||||
}
|
}
|
||||||
|
|
||||||
function pageRouting(baseUrl) {
|
function page(baseUrl) {
|
||||||
const gr = regex => regex.toString().replace(/(^\/|\/$)/gm, '');
|
const gr = regex => regex.toString().replace(/(^\/|\/$)/gm, '');
|
||||||
return new RegExp(
|
return new RegExp(
|
||||||
`(?!${gr(docsRouting(baseUrl))}|${gr(
|
`(?!${gr(docs(baseUrl))}|${gr(blog(baseUrl))})^${baseUrl}.*.html$`
|
||||||
blogRouting(baseUrl)
|
|
||||||
)})^${baseUrl}.*.html$`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sitemapRouting(baseUrl) {
|
function sitemap(baseUrl) {
|
||||||
return new RegExp(`^${baseUrl}sitemap.xml$`);
|
return new RegExp(`^${baseUrl}sitemap.xml$`);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
blogRouting,
|
blog,
|
||||||
docsRouting,
|
docs,
|
||||||
dotRouting,
|
dotfiles,
|
||||||
feedRouting,
|
feed,
|
||||||
pageRouting,
|
page,
|
||||||
noExtRouting,
|
noExtension,
|
||||||
sitemapRouting,
|
sitemap,
|
||||||
};
|
};
|
|
@ -18,17 +18,9 @@ function execute(port, options) {
|
||||||
const request = require('request');
|
const request = require('request');
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const getTOC = require('../core/getTOC');
|
const {insertTOC} = require('../core/toc');
|
||||||
const utils = require('../core/utils');
|
const {getPath} = require('../core/utils');
|
||||||
const {
|
const {isSeparateCss} = require('./utils');
|
||||||
blogRouting,
|
|
||||||
docsRouting,
|
|
||||||
dotRouting,
|
|
||||||
feedRouting,
|
|
||||||
pageRouting,
|
|
||||||
noExtRouting,
|
|
||||||
sitemapRouting,
|
|
||||||
} = require('../core/routing');
|
|
||||||
const mkdirp = require('mkdirp');
|
const mkdirp = require('mkdirp');
|
||||||
const glob = require('glob');
|
const glob = require('glob');
|
||||||
const chalk = require('chalk');
|
const chalk = require('chalk');
|
||||||
|
@ -41,6 +33,7 @@ function execute(port, options) {
|
||||||
|
|
||||||
const feed = require('./feed');
|
const feed = require('./feed');
|
||||||
const sitemap = require('./sitemap');
|
const sitemap = require('./sitemap');
|
||||||
|
const routing = require('./routing');
|
||||||
|
|
||||||
const CWD = process.cwd();
|
const CWD = process.cwd();
|
||||||
|
|
||||||
|
@ -101,32 +94,6 @@ function execute(port, options) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TABLE_OF_CONTENTS_TOKEN = '<AUTOGENERATED_TABLE_OF_CONTENTS>';
|
|
||||||
|
|
||||||
const insertTableOfContents = rawContent => {
|
|
||||||
const filterRe = /^`[^`]*`/;
|
|
||||||
const headers = getTOC(rawContent, 'h3', null);
|
|
||||||
|
|
||||||
const tableOfContents = headers
|
|
||||||
.filter(header => filterRe.test(header.rawContent))
|
|
||||||
.map(header => ` - [${header.rawContent}](#${header.hashLink})`)
|
|
||||||
.join('\n');
|
|
||||||
|
|
||||||
return rawContent.replace(TABLE_OF_CONTENTS_TOKEN, tableOfContents);
|
|
||||||
};
|
|
||||||
|
|
||||||
function isSeparateCss(file) {
|
|
||||||
if (!siteConfig.separateCss) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (let i = 0; i < siteConfig.separateCss.length; i++) {
|
|
||||||
if (file.includes(siteConfig.separateCss[i])) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function requestFile(url, res, notFoundCallback) {
|
function requestFile(url, res, notFoundCallback) {
|
||||||
request.get(url, (error, response, body) => {
|
request.get(url, (error, response, body) => {
|
||||||
if (!error) {
|
if (!error) {
|
||||||
|
@ -183,7 +150,7 @@ function execute(port, options) {
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
// handle all requests for document pages
|
// handle all requests for document pages
|
||||||
app.get(docsRouting(siteConfig.baseUrl), (req, res, next) => {
|
app.get(routing.docs(siteConfig.baseUrl), (req, res, next) => {
|
||||||
const url = req.path.toString().replace(siteConfig.baseUrl, '');
|
const url = req.path.toString().replace(siteConfig.baseUrl, '');
|
||||||
|
|
||||||
// links is a map from a permalink to an id for each document
|
// links is a map from a permalink to an id for each document
|
||||||
|
@ -193,23 +160,7 @@ function execute(port, options) {
|
||||||
links[metadata.permalink] = id;
|
links[metadata.permalink] = id;
|
||||||
});
|
});
|
||||||
|
|
||||||
// mdToHtml is a map from a markdown file name to its html link, used to
|
const mdToHtml = metadataUtils.mdToHtml(Metadata, siteConfig.baseUrl);
|
||||||
// change relative markdown links that work on GitHub into actual site links
|
|
||||||
const mdToHtml = {};
|
|
||||||
Object.keys(Metadata).forEach(id => {
|
|
||||||
const metadata = Metadata[id];
|
|
||||||
if (metadata.language !== 'en' || metadata.original_id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let htmlLink =
|
|
||||||
siteConfig.baseUrl + metadata.permalink.replace('/next/', '/');
|
|
||||||
if (htmlLink.includes('/docs/en/')) {
|
|
||||||
htmlLink = htmlLink.replace('/docs/en/', '/docs/en/VERSION/');
|
|
||||||
} else {
|
|
||||||
htmlLink = htmlLink.replace('/docs/', '/docs/VERSION/');
|
|
||||||
}
|
|
||||||
mdToHtml[metadata.source] = htmlLink;
|
|
||||||
});
|
|
||||||
|
|
||||||
const metadata = Metadata[links[url]];
|
const metadata = Metadata[links[url]];
|
||||||
if (!metadata) {
|
if (!metadata) {
|
||||||
|
@ -242,16 +193,14 @@ function execute(port, options) {
|
||||||
).rawContent;
|
).rawContent;
|
||||||
|
|
||||||
// generate table of contents if appropriate
|
// generate table of contents if appropriate
|
||||||
if (rawContent && rawContent.indexOf(TABLE_OF_CONTENTS_TOKEN) !== -1) {
|
rawContent = insertTOC(rawContent);
|
||||||
rawContent = insertTableOfContents(rawContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
const defaultVersion = env.versioning.defaultVersion;
|
const defaultVersion = env.versioning.defaultVersion;
|
||||||
|
|
||||||
// replace any links to markdown files to their website html links
|
// replace any links to markdown files to their website html links
|
||||||
Object.keys(mdToHtml).forEach(key => {
|
Object.keys(mdToHtml).forEach(key => {
|
||||||
let link = mdToHtml[key];
|
let link = mdToHtml[key];
|
||||||
link = utils.getPath(link, siteConfig.cleanUrl);
|
link = getPath(link, siteConfig.cleanUrl);
|
||||||
link = link.replace('/en/', `/${language}/`);
|
link = link.replace('/en/', `/${language}/`);
|
||||||
link = link.replace(
|
link = link.replace(
|
||||||
'/VERSION/',
|
'/VERSION/',
|
||||||
|
@ -259,14 +208,9 @@ function execute(port, options) {
|
||||||
? `/${metadata.version}/`
|
? `/${metadata.version}/`
|
||||||
: '/'
|
: '/'
|
||||||
);
|
);
|
||||||
// replace relative links without "./"
|
// replace relative links with & without "./"
|
||||||
rawContent = rawContent.replace(
|
rawContent = rawContent.replace(
|
||||||
new RegExp(`\\]\\(${key}`, 'g'),
|
new RegExp(`\\]\\((${key}|\\./${key})`, 'g'),
|
||||||
`](${link}`
|
|
||||||
);
|
|
||||||
// replace relative links with "./"
|
|
||||||
rawContent = rawContent.replace(
|
|
||||||
new RegExp(`\\]\\(\\./${key}`, 'g'),
|
|
||||||
`](${link}`
|
`](${link}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -305,7 +249,7 @@ function execute(port, options) {
|
||||||
res.send(renderToStaticMarkupWithDoctype(docComp));
|
res.send(renderToStaticMarkupWithDoctype(docComp));
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get(sitemapRouting(siteConfig.baseUrl), (req, res) => {
|
app.get(routing.sitemap(siteConfig.baseUrl), (req, res) => {
|
||||||
sitemap((err, xml) => {
|
sitemap((err, xml) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
res.status(500).send('Sitemap error');
|
res.status(500).send('Sitemap error');
|
||||||
|
@ -316,7 +260,7 @@ function execute(port, options) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get(feedRouting(siteConfig.baseUrl), (req, res, next) => {
|
app.get(routing.feed(siteConfig.baseUrl), (req, res, next) => {
|
||||||
res.set('Content-Type', 'application/rss+xml');
|
res.set('Content-Type', 'application/rss+xml');
|
||||||
const file = req.path
|
const file = req.path
|
||||||
.toString()
|
.toString()
|
||||||
|
@ -331,7 +275,7 @@ function execute(port, options) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle all requests for blog pages and posts.
|
// Handle all requests for blog pages and posts.
|
||||||
app.get(blogRouting(siteConfig.baseUrl), (req, res, next) => {
|
app.get(routing.blog(siteConfig.baseUrl), (req, res, next) => {
|
||||||
// Regenerate the blog metadata in case it has changed. Consider improving
|
// Regenerate the blog metadata in case it has changed. Consider improving
|
||||||
// this to regenerate on file save rather than on page request.
|
// this to regenerate on file save rather than on page request.
|
||||||
reloadMetadataBlog();
|
reloadMetadataBlog();
|
||||||
|
@ -421,7 +365,7 @@ function execute(port, options) {
|
||||||
});
|
});
|
||||||
|
|
||||||
// handle all other main pages
|
// handle all other main pages
|
||||||
app.get(pageRouting(siteConfig.baseUrl), (req, res, next) => {
|
app.get(routing.page(siteConfig.baseUrl), (req, res, next) => {
|
||||||
// Look for user-provided HTML file first.
|
// Look for user-provided HTML file first.
|
||||||
let htmlFile = req.path.toString().replace(siteConfig.baseUrl, '');
|
let htmlFile = req.path.toString().replace(siteConfig.baseUrl, '');
|
||||||
htmlFile = join(CWD, 'pages', htmlFile);
|
htmlFile = join(CWD, 'pages', htmlFile);
|
||||||
|
@ -541,7 +485,7 @@ function execute(port, options) {
|
||||||
const files = glob.sync(join(CWD, 'static', '**', '*.css'));
|
const files = glob.sync(join(CWD, 'static', '**', '*.css'));
|
||||||
|
|
||||||
files.forEach(file => {
|
files.forEach(file => {
|
||||||
if (isSeparateCss(file)) {
|
if (isSeparateCss(file, siteConfig.separateCss)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cssContent = `${cssContent}\n${fs.readFileSync(file, {
|
cssContent = `${cssContent}\n${fs.readFileSync(file, {
|
||||||
|
@ -596,7 +540,7 @@ function execute(port, options) {
|
||||||
|
|
||||||
// "redirect" requests to pages ending with "/" or no extension so that,
|
// "redirect" requests to pages ending with "/" or no extension so that,
|
||||||
// for example, request to "blog" returns "blog/index.html" or "blog.html"
|
// for example, request to "blog" returns "blog/index.html" or "blog.html"
|
||||||
app.get(noExtRouting(), (req, res, next) => {
|
app.get(routing.noExtension(), (req, res, next) => {
|
||||||
const slash = req.path.toString().endsWith('/') ? '' : '/';
|
const slash = req.path.toString().endsWith('/') ? '' : '/';
|
||||||
const requestUrl = `http://localhost:${port}${req.path}`;
|
const requestUrl = `http://localhost:${port}${req.path}`;
|
||||||
requestFile(`${requestUrl + slash}index.html`, res, () => {
|
requestFile(`${requestUrl + slash}index.html`, res, () => {
|
||||||
|
@ -612,7 +556,7 @@ function execute(port, options) {
|
||||||
|
|
||||||
// handle special cleanUrl case like '/blog/1.2.3' & '/blog.robots.hai'
|
// handle special cleanUrl case like '/blog/1.2.3' & '/blog.robots.hai'
|
||||||
// where we should try to serve 'blog/1.2.3.html' & '/blog.robots.hai.html'
|
// where we should try to serve 'blog/1.2.3.html' & '/blog.robots.hai.html'
|
||||||
app.get(dotRouting(), (req, res, next) => {
|
app.get(routing.dotfiles(), (req, res, next) => {
|
||||||
if (!siteConfig.cleanUrl) {
|
if (!siteConfig.cleanUrl) {
|
||||||
next();
|
next();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -9,23 +9,14 @@ const cssnano = require('cssnano');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const escapeStringRegexp = require('escape-string-regexp');
|
const escapeStringRegexp = require('escape-string-regexp');
|
||||||
|
|
||||||
// Return the subdirectory path from a reference directory
|
|
||||||
// Example:
|
|
||||||
// (file: 'docs/projectA/test.md', refDir: 'docs')
|
|
||||||
// returns 'projectA'
|
|
||||||
function getSubDir(file, refDir) {
|
function getSubDir(file, refDir) {
|
||||||
let subDir = path.dirname(path.relative(refDir, file));
|
const subDir = path.dirname(path.relative(refDir, file)).replace('\\', '/');
|
||||||
subDir = subDir.replace('\\', '/');
|
return subDir !== '.' && !subDir.includes('..') ? subDir : null;
|
||||||
return subDir !== '.' ? subDir : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the corresponding enabled language locale of a file.
|
|
||||||
// Example:
|
|
||||||
// (file: '/website/translated_docs/ko/projectA/test.md', refDir: 'website/translated_docs')
|
|
||||||
// returns 'ko'
|
|
||||||
function getLanguage(file, refDir) {
|
function getLanguage(file, refDir) {
|
||||||
const regexSubFolder = new RegExp(
|
const regexSubFolder = new RegExp(
|
||||||
`/${escapeStringRegexp(path.basename(refDir))}/(.*)/.*/`
|
`${escapeStringRegexp(path.basename(refDir))}/(.*?)/.*`
|
||||||
);
|
);
|
||||||
const match = regexSubFolder.exec(file);
|
const match = regexSubFolder.exec(file);
|
||||||
|
|
||||||
|
@ -42,6 +33,18 @@ function getLanguage(file, refDir) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isSeparateCss(file, separateDirs) {
|
||||||
|
if (!separateDirs) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < separateDirs.length; i++) {
|
||||||
|
if (file.includes(separateDirs[i])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
function minifyCss(cssContent) {
|
function minifyCss(cssContent) {
|
||||||
return cssnano
|
return cssnano
|
||||||
.process(cssContent, {
|
.process(cssContent, {
|
||||||
|
@ -54,5 +57,6 @@ function minifyCss(cssContent) {
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getSubDir,
|
getSubDir,
|
||||||
getLanguage,
|
getLanguage,
|
||||||
|
isSeparateCss,
|
||||||
minifyCss,
|
minifyCss,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue