Add Prettier Formatting (#258)

* Add Prettier formatting to source files and example files, and check that Prettier formatting is maintained on PRs

* Remove trailing-comma as we are using Node 6 on Circle

* Use latest Node 6 LTS version in Circle

* Remove unused test
This commit is contained in:
Héctor Ramos 2017-12-04 19:21:02 -08:00 committed by Joel Marcey
parent 0cead4b6f9
commit 65421db62e
50 changed files with 1376 additions and 1350 deletions

View file

@ -26,36 +26,27 @@ aliases:
defaults: &defaults defaults: &defaults
working_directory: ~/docusaurus working_directory: ~/docusaurus
docker:
- image: circleci/node:6
version: 2 version: 2
jobs: jobs:
test-js-node:
<<: *defaults
docker:
- image: circleci/node:6.11.4
steps:
- checkout
- restore-cache: *restore-yarn-cache
- run: *yarn
- save-cache: *save-yarn-cache
- run: yarn run test
test-website: test-website:
<<: *defaults <<: *defaults
docker:
- image: circleci/node:6.11.4
steps: steps:
- checkout - checkout
- restore-cache: *restore-yarn-cache - restore-cache: *restore-yarn-cache
- run: *yarn - run: *yarn
- save-cache: *save-yarn-cache - save-cache: *save-yarn-cache
- run:
name: Check Prettier
command: yarn ci-check
- run: - run:
name: Test Build Static Website name: Test Build Static Website
command: cd website && yarn run build command: cd website && yarn run build
deploy-website: deploy-website:
<<: *defaults <<: *defaults
docker:
- image: circleci/node:6.11.4
steps: steps:
- add_ssh_keys: - add_ssh_keys:
fingerprints: fingerprints:
@ -84,8 +75,6 @@ jobs:
publish-npm: publish-npm:
<<: *defaults <<: *defaults
docker:
- image: circleci/node:6.11.4
steps: steps:
- checkout - checkout
- restore-cache: *restore-yarn-cache - restore-cache: *restore-yarn-cache
@ -105,11 +94,6 @@ jobs:
workflows: workflows:
version: 2 version: 2
test_node:
jobs:
- test-js-node:
filters: *filter-ignore-gh-pages
website: website:
jobs: jobs:
- test-website: - test-website:

9
.prettierrc Normal file
View file

@ -0,0 +1,9 @@
{
"bracketSpacing": false,
"jsxBracketSameLine": true,
"parser": "flow",
"printWidth": 80,
"proseWrap": false,
"singleQuote": true,
"trailingComma": "es5"
}

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
class Footer extends React.Component { class Footer extends React.Component {
render() { render() {
@ -26,31 +26,28 @@ class Footer extends React.Component {
<a <a
href={ href={
this.props.config.baseUrl + this.props.config.baseUrl +
"docs/" + 'docs/' +
this.props.language + this.props.language +
"/doc1.html" '/doc1.html'
} }>
>
Getting Started (or other categories) Getting Started (or other categories)
</a> </a>
<a <a
href={ href={
this.props.config.baseUrl + this.props.config.baseUrl +
"docs/" + 'docs/' +
this.props.language + this.props.language +
"/doc2.html" '/doc2.html'
} }>
>
Guides (or other categories) Guides (or other categories)
</a> </a>
<a <a
href={ href={
this.props.config.baseUrl + this.props.config.baseUrl +
"docs/" + 'docs/' +
this.props.language + this.props.language +
"/doc3.html" '/doc3.html'
} }>
>
API Reference (or other categories) API Reference (or other categories)
</a> </a>
</div> </div>
@ -58,15 +55,13 @@ class Footer extends React.Component {
<h5>Community</h5> <h5>Community</h5>
<a <a
href={ href={
this.props.config.baseUrl + this.props.language + "/users.html" this.props.config.baseUrl + this.props.language + '/users.html'
} }>
>
User Showcase User Showcase
</a> </a>
<a <a
href="http://stackoverflow.com/questions/tagged/" href="http://stackoverflow.com/questions/tagged/"
target="_blank" target="_blank">
>
Stack Overflow Stack Overflow
</a> </a>
<a href="https://discordapp.com/">Project Chat</a> <a href="https://discordapp.com/">Project Chat</a>
@ -76,28 +71,27 @@ class Footer extends React.Component {
</div> </div>
<div> <div>
<h5>More</h5> <h5>More</h5>
<a href={this.props.config.baseUrl + "blog"}>Blog</a> <a href={this.props.config.baseUrl + 'blog'}>Blog</a>
<a href="https://github.com/">GitHub</a> <a href="https://github.com/">GitHub</a>
<a className="github-button" <a
className="github-button"
href={this.props.config.repoUrl} href={this.props.config.repoUrl}
data-icon="octicon-star" data-icon="octicon-star"
data-count-href="/deltice/test-site/stargazers" data-count-href="/deltice/test-site/stargazers"
data-show-count={true} data-show-count={true}
data-count-aria-label="# stargazers on GitHub" data-count-aria-label="# stargazers on GitHub"
aria-label="Star this project on GitHub" aria-label="Star this project on GitHub">
>
Star Star
</a> </a>
</div> </div>
</section> </section>
<a <a
href="https://code.facebook.com/projects/" href="https://code.facebook.com/projects/"
target="_blank" target="_blank"
className="fbOpenSource" className="fbOpenSource">
>
<img <img
src={this.props.config.baseUrl + "img/oss_logo.png"} src={this.props.config.baseUrl + 'img/oss_logo.png'}
alt="Facebook Open Source" alt="Facebook Open Source"
width="170" width="170"
height="45" height="45"

View file

@ -5,31 +5,30 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
const CompLibrary = require("../../core/CompLibrary.js"); const CompLibrary = require('../../core/CompLibrary.js');
const Container = CompLibrary.Container; const Container = CompLibrary.Container;
const GridBlock = CompLibrary.GridBlock; const GridBlock = CompLibrary.GridBlock;
const siteConfig = require(process.cwd() + "/siteConfig.js"); const siteConfig = require(process.cwd() + '/siteConfig.js');
class Help extends React.Component { class Help extends React.Component {
render() { render() {
const supportLinks = [ const supportLinks = [
{ {
content: content:
"Learn more using the [documentation on this site.](/test-site/docs/en/doc1.html)", 'Learn more using the [documentation on this site.](/test-site/docs/en/doc1.html)',
title: "Browse Docs" title: 'Browse Docs',
}, },
{ {
content: "Ask questions about the documentation and project", content: 'Ask questions about the documentation and project',
title: "Join the community" title: 'Join the community',
}, },
{ {
content: "Find out what's new with this project", content: "Find out what's new with this project",
title: "Stay up to date" title: 'Stay up to date',
} },
]; ];
return ( return (

View file

@ -5,14 +5,14 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
const CompLibrary = require("../../core/CompLibrary.js"); const CompLibrary = require('../../core/CompLibrary.js');
const MarkdownBlock = CompLibrary.MarkdownBlock; /* Used to read markdown */ const MarkdownBlock = CompLibrary.MarkdownBlock; /* Used to read markdown */
const Container = CompLibrary.Container; const Container = CompLibrary.Container;
const GridBlock = CompLibrary.GridBlock; const GridBlock = CompLibrary.GridBlock;
const siteConfig = require(process.cwd() + "/siteConfig.js"); const siteConfig = require(process.cwd() + '/siteConfig.js');
class Button extends React.Component { class Button extends React.Component {
render() { render() {
@ -27,7 +27,7 @@ class Button extends React.Component {
} }
Button.defaultProps = { Button.defaultProps = {
target: "_self" target: '_self',
}; };
class HomeSplash extends React.Component { class HomeSplash extends React.Component {
@ -37,14 +37,12 @@ class HomeSplash extends React.Component {
<div className="homeSplashFade"> <div className="homeSplashFade">
<div className="wrapper homeWrapper"> <div className="wrapper homeWrapper">
<div className="projectLogo"> <div className="projectLogo">
<img src={siteConfig.baseUrl + "img/docusaurus.svg"} /> <img src={siteConfig.baseUrl + 'img/docusaurus.svg'} />
</div> </div>
<div className="inner"> <div className="inner">
<h2 className="projectTitle"> <h2 className="projectTitle">
{siteConfig.title} {siteConfig.title}
<small> <small>{siteConfig.tagline}</small>
{siteConfig.tagline}
</small>
</h2> </h2>
<div className="section promoSection"> <div className="section promoSection">
<div className="promoRow"> <div className="promoRow">
@ -53,21 +51,19 @@ class HomeSplash extends React.Component {
<Button <Button
href={ href={
siteConfig.baseUrl + siteConfig.baseUrl +
"docs/" + 'docs/' +
this.props.language + this.props.language +
"/doc1.html" '/doc1.html'
} }>
>
Example Link Example Link
</Button> </Button>
<Button <Button
href={ href={
siteConfig.baseUrl + siteConfig.baseUrl +
"docs/" + 'docs/' +
this.props.language + this.props.language +
"/doc2.html" '/doc2.html'
} }>
>
Example Link 2 Example Link 2
</Button> </Button>
</div> </div>
@ -83,7 +79,7 @@ class HomeSplash extends React.Component {
class Index extends React.Component { class Index extends React.Component {
render() { render() {
let language = this.props.language || "en"; let language = this.props.language || 'en';
const showcase = siteConfig.users const showcase = siteConfig.users
.filter(user => { .filter(user => {
return user.pinned; return user.pinned;
@ -100,22 +96,22 @@ class Index extends React.Component {
<div> <div>
<HomeSplash language={language} /> <HomeSplash language={language} />
<div className="mainContainer"> <div className="mainContainer">
<Container padding={["bottom", "top"]}> <Container padding={['bottom', 'top']}>
<GridBlock <GridBlock
align="center" align="center"
contents={[ contents={[
{ {
content: "This is the content of my feature", content: 'This is the content of my feature',
image: siteConfig.baseUrl + "img/docusaurus.svg", image: siteConfig.baseUrl + 'img/docusaurus.svg',
imageAlign: "top", imageAlign: 'top',
title: "Feature One" title: 'Feature One',
}, },
{ {
content: "The content of my second feature", content: 'The content of my second feature',
image: siteConfig.baseUrl + "img/docusaurus.svg", image: siteConfig.baseUrl + 'img/docusaurus.svg',
imageAlign: "top", imageAlign: 'top',
title: "Feature Two" title: 'Feature Two',
} },
]} ]}
layout="fourColumn" layout="fourColumn"
/> />
@ -123,67 +119,61 @@ class Index extends React.Component {
<div <div
className="productShowcaseSection paddingBottom" className="productShowcaseSection paddingBottom"
style={{ textAlign: "center" }} style={{textAlign: 'center'}}>
>
<h2>Feature Callout</h2> <h2>Feature Callout</h2>
<MarkdownBlock>These are features of this project</MarkdownBlock> <MarkdownBlock>These are features of this project</MarkdownBlock>
</div> </div>
<Container padding={["bottom", "top"]} background="light"> <Container padding={['bottom', 'top']} background="light">
<GridBlock <GridBlock
contents={[ contents={[
{ {
content: "Talk about learning how to use this", content: 'Talk about learning how to use this',
image: siteConfig.baseUrl + "img/docusaurus.svg", image: siteConfig.baseUrl + 'img/docusaurus.svg',
imageAlign: "right", imageAlign: 'right',
title: "Learn How" title: 'Learn How',
} },
]} ]}
/> />
</Container> </Container>
<Container padding={["bottom", "top"]} id="try"> <Container padding={['bottom', 'top']} id="try">
<GridBlock <GridBlock
contents={[ contents={[
{ {
content: "Talk about trying this out", content: 'Talk about trying this out',
image: siteConfig.baseUrl + "img/docusaurus.svg", image: siteConfig.baseUrl + 'img/docusaurus.svg',
imageAlign: "left", imageAlign: 'left',
title: "Try it Out" title: 'Try it Out',
} },
]} ]}
/> />
</Container> </Container>
<Container padding={["bottom", "top"]} background="dark"> <Container padding={['bottom', 'top']} background="dark">
<GridBlock <GridBlock
contents={[ contents={[
{ {
content: content:
"This is another description of how this project is useful", 'This is another description of how this project is useful',
image: siteConfig.baseUrl + "img/docusaurus.svg", image: siteConfig.baseUrl + 'img/docusaurus.svg',
imageAlign: "right", imageAlign: 'right',
title: "Description" title: 'Description',
} },
]} ]}
/> />
</Container> </Container>
<div className="productShowcaseSection paddingBottom"> <div className="productShowcaseSection paddingBottom">
<h2> <h2>{"Who's Using This?"}</h2>
{"Who's Using This?"}
</h2>
<p>This project is used by all these people</p> <p>This project is used by all these people</p>
<div className="logos"> <div className="logos">{showcase}</div>
{showcase}
</div>
<div className="more-users"> <div className="more-users">
<a <a
className="button" className="button"
href={ href={
siteConfig.baseUrl + this.props.language + "/" + "users.html" siteConfig.baseUrl + this.props.language + '/' + 'users.html'
} }>
>
More {siteConfig.title} Users More {siteConfig.title} Users
</a> </a>
</div> </div>

View file

@ -5,12 +5,12 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
const CompLibrary = require("../../core/CompLibrary.js"); const CompLibrary = require('../../core/CompLibrary.js');
const Container = CompLibrary.Container; const Container = CompLibrary.Container;
const siteConfig = require(process.cwd() + "/siteConfig.js"); const siteConfig = require(process.cwd() + '/siteConfig.js');
class Users extends React.Component { class Users extends React.Component {
render() { render() {
@ -24,7 +24,7 @@ class Users extends React.Component {
return ( return (
<div className="mainContainer"> <div className="mainContainer">
<Container padding={["bottom", "top"]}> <Container padding={['bottom', 'top']}>
<div className="showcaseSection"> <div className="showcaseSection">
<div className="prose"> <div className="prose">
<h1>Who's Using This?</h1> <h1>Who's Using This?</h1>

View file

@ -8,49 +8,47 @@
/* List of projects/orgs using your project for the users page */ /* List of projects/orgs using your project for the users page */
const users = [ const users = [
{ {
caption: "User1", caption: 'User1',
image: "/test-site/img/docusaurus.svg", image: '/test-site/img/docusaurus.svg',
infoLink: "https://www.example.com", infoLink: 'https://www.example.com',
pinned: true pinned: true,
} },
]; ];
const siteConfig = { const siteConfig = {
title: "Test Site" /* title for your website */, title: 'Test Site' /* title for your website */,
tagline: "A website for testing", tagline: 'A website for testing',
url: "https://deltice.github.io" /* your website url */, url: 'https://deltice.github.io' /* your website url */,
baseUrl: "/test-site/" /* base url for your project */, baseUrl: '/test-site/' /* base url for your project */,
projectName: "test-site", projectName: 'test-site',
headerLinks: [ headerLinks: [
{ doc: "doc1", label: "Docs" }, {doc: 'doc1', label: 'Docs'},
{ doc: "doc4", label: "API" }, {doc: 'doc4', label: 'API'},
{ page: "help", label: "Help" }, {page: 'help', label: 'Help'},
{ blog: true, label: "Blog" } {blog: true, label: 'Blog'},
], ],
users, users,
/* path to images for header/footer */ /* path to images for header/footer */
headerIcon: "img/docusaurus.svg", headerIcon: 'img/docusaurus.svg',
footerIcon: "img/docusaurus.svg", footerIcon: 'img/docusaurus.svg',
favicon: "img/favicon.png", favicon: 'img/favicon.png',
/* colors for website */ /* colors for website */
colors: { colors: {
primaryColor: "#2E8555", primaryColor: '#2E8555',
secondaryColor: "#205C3B" secondaryColor: '#205C3B',
}, },
// This copyright info is used in /core/Footer.js and blog rss/atom feeds. // This copyright info is used in /core/Footer.js and blog rss/atom feeds.
copyright: copyright:
"Copyright © " + 'Copyright © ' +
new Date().getFullYear() + new Date().getFullYear() +
" Your Name or Your Company Name", ' Your Name or Your Company Name',
highlight: { highlight: {
// Highlight.js theme to use for syntax highlighting in code blocks // Highlight.js theme to use for syntax highlighting in code blocks
theme: "default" theme: 'default',
}, },
scripts: [ scripts: ['https://buttons.github.io/buttons.js'],
"https://buttons.github.io/buttons.js"
],
// You may provide arbitrary config keys to be used as needed by your template. // You may provide arbitrary config keys to be used as needed by your template.
repoUrl: "https://github.com/deltice/test-site", repoUrl: 'https://github.com/deltice/test-site',
}; };
module.exports = siteConfig; module.exports = siteConfig;

View file

@ -8,174 +8,174 @@
const languages = [ const languages = [
{ {
enabled: true, enabled: true,
name: "English", name: 'English',
tag: "en" tag: 'en',
}, },
{ {
enabled: false, enabled: false,
name: "日本語", name: '日本語',
tag: "ja" tag: 'ja',
}, },
{ {
enabled: false, enabled: false,
name: "العربية", name: 'العربية',
tag: "ar" tag: 'ar',
}, },
{ {
enabled: false, enabled: false,
name: "Bosanski", name: 'Bosanski',
tag: "bs-BA" tag: 'bs-BA',
}, },
{ {
enabled: false, enabled: false,
name: "Català", name: 'Català',
tag: "ca" tag: 'ca',
}, },
{ {
enabled: false, enabled: false,
name: "Čeština", name: 'Čeština',
tag: "cs" tag: 'cs',
}, },
{ {
enabled: false, enabled: false,
name: "Dansk", name: 'Dansk',
tag: "da" tag: 'da',
}, },
{ {
enabled: false, enabled: false,
name: "Deutsch", name: 'Deutsch',
tag: "de" tag: 'de',
}, },
{ {
enabled: false, enabled: false,
name: "Ελληνικά", name: 'Ελληνικά',
tag: "el" tag: 'el',
}, },
{ {
enabled: false, enabled: false,
name: "Español", name: 'Español',
tag: "es-ES" tag: 'es-ES',
}, },
{ {
enabled: false, enabled: false,
name: "فارسی", name: 'فارسی',
tag: "fa-IR" tag: 'fa-IR',
}, },
{ {
enabled: false, enabled: false,
name: "Suomi", name: 'Suomi',
tag: "fi" tag: 'fi',
}, },
{ {
enabled: false, enabled: false,
name: "Français", name: 'Français',
tag: "fr" tag: 'fr',
}, },
{ {
enabled: false, enabled: false,
name: "עִברִית", name: 'עִברִית',
tag: "he" tag: 'he',
}, },
{ {
enabled: false, enabled: false,
name: "Magyar", name: 'Magyar',
tag: "hu" tag: 'hu',
}, },
{ {
enabled: false, enabled: false,
name: "Bahasa Indonesia", name: 'Bahasa Indonesia',
tag: "id-ID" tag: 'id-ID',
}, },
{ {
enabled: false, enabled: false,
name: "Italiano", name: 'Italiano',
tag: "it" tag: 'it',
}, },
{ {
enabled: false, enabled: false,
name: "Afrikaans", name: 'Afrikaans',
tag: "af" tag: 'af',
}, },
{ {
enabled: false, enabled: false,
name: "한국어", name: '한국어',
tag: "ko" tag: 'ko',
}, },
{ {
enabled: false, enabled: false,
name: "मराठी", name: 'मराठी',
tag: "mr-IN" tag: 'mr-IN',
}, },
{ {
enabled: false, enabled: false,
name: "Nederlands", name: 'Nederlands',
tag: "nl" tag: 'nl',
}, },
{ {
enabled: false, enabled: false,
name: "Norsk", name: 'Norsk',
tag: "no-NO" tag: 'no-NO',
}, },
{ {
enabled: false, enabled: false,
name: "Polskie", name: 'Polskie',
tag: "pl" tag: 'pl',
}, },
{ {
enabled: false, enabled: false,
name: "Português", name: 'Português',
tag: "pt-PT" tag: 'pt-PT',
}, },
{ {
enabled: false, enabled: false,
name: "Português (Brasil)", name: 'Português (Brasil)',
tag: "pt-BR" tag: 'pt-BR',
}, },
{ {
enabled: false, enabled: false,
name: "Română", name: 'Română',
tag: "ro" tag: 'ro',
}, },
{ {
enabled: false, enabled: false,
name: "Русский", name: 'Русский',
tag: "ru" tag: 'ru',
}, },
{ {
enabled: false, enabled: false,
name: "Slovenský", name: 'Slovenský',
tag: "sk-SK" tag: 'sk-SK',
}, },
{ {
enabled: false, enabled: false,
name: "Српски језик (Ћирилица)", name: 'Српски језик (Ћирилица)',
tag: "sr" tag: 'sr',
}, },
{ {
enabled: false, enabled: false,
name: "Svenska", name: 'Svenska',
tag: "sv-SE" tag: 'sv-SE',
}, },
{ {
enabled: false, enabled: false,
name: "Türkçe", name: 'Türkçe',
tag: "tr" tag: 'tr',
}, },
{ {
enabled: false, enabled: false,
name: "Українська", name: 'Українська',
tag: "uk" tag: 'uk',
}, },
{ {
enabled: false, enabled: false,
name: "Tiếng Việt", name: 'Tiếng Việt',
tag: "vi" tag: 'vi',
}, },
{ {
enabled: false, enabled: false,
name: "中文", name: '中文',
tag: "zh-Hans" tag: 'zh-Hans',
}, },
{ enabled: false, name: "繁體中文", tag: "zh-Hant" } {enabled: false, name: '繁體中文', tag: 'zh-Hant'},
]; ];
module.exports = languages; module.exports = languages;

View file

@ -5,15 +5,15 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
const CompLibrary = require("../../core/CompLibrary.js"); const CompLibrary = require('../../core/CompLibrary.js');
const Container = CompLibrary.Container; const Container = CompLibrary.Container;
const GridBlock = CompLibrary.GridBlock; const GridBlock = CompLibrary.GridBlock;
const translate = require("../../server/translate.js").translate; const translate = require('../../server/translate.js').translate;
const siteConfig = require(process.cwd() + "/siteConfig.js"); const siteConfig = require(process.cwd() + '/siteConfig.js');
class Help extends React.Component { class Help extends React.Component {
render() { render() {
@ -21,10 +21,11 @@ class Help extends React.Component {
{ {
content: ( content: (
<translate> <translate>
Learn more using the [documentation on this site.](/test-site/docs/en/doc1.html) Learn more using the [documentation on this
site.](/test-site/docs/en/doc1.html)
</translate> </translate>
), ),
title: <translate>Browse Docs</translate> title: <translate>Browse Docs</translate>,
}, },
{ {
content: ( content: (
@ -32,12 +33,12 @@ class Help extends React.Component {
Ask questions about the documentation and project Ask questions about the documentation and project
</translate> </translate>
), ),
title: <translate>Join the community</translate> title: <translate>Join the community</translate>,
}, },
{ {
content: <translate>Find out what's new with this project</translate>, content: <translate>Find out what's new with this project</translate>,
title: <translate>Stay up to date</translate> title: <translate>Stay up to date</translate>,
} },
]; ];
return ( return (
@ -63,7 +64,7 @@ class Help extends React.Component {
} }
Help.defaultProps = { Help.defaultProps = {
language: "en" language: 'en',
}; };
module.exports = Help; module.exports = Help;

View file

@ -5,16 +5,16 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
const CompLibrary = require("../../core/CompLibrary"); const CompLibrary = require('../../core/CompLibrary');
const Container = CompLibrary.Container; const Container = CompLibrary.Container;
const GridBlock = CompLibrary.GridBlock; const GridBlock = CompLibrary.GridBlock;
const CWD = process.cwd(); const CWD = process.cwd();
const siteConfig = require(CWD + "/siteConfig.js"); const siteConfig = require(CWD + '/siteConfig.js');
const versions = require(CWD + "/versions.json"); const versions = require(CWD + '/versions.json');
class Versions extends React.Component { class Versions extends React.Component {
render() { render() {
@ -24,7 +24,7 @@ class Versions extends React.Component {
<Container className="mainContainer versionsContainer"> <Container className="mainContainer versionsContainer">
<div className="post"> <div className="post">
<header className="postHeader"> <header className="postHeader">
<h2>{siteConfig.title + " Versions"}</h2> <h2>{siteConfig.title + ' Versions'}</h2>
</header> </header>
<p>New versions of this project are released every so often.</p> <p>New versions of this project are released every so often.</p>
<a name="latest" /> <a name="latest" />
@ -32,14 +32,12 @@ class Versions extends React.Component {
<table className="versions"> <table className="versions">
<tbody> <tbody>
<tr> <tr>
<th> <th>{latestVersion}</th>
{latestVersion}
</th>
<td> <td>
<a href={""}>Documentation</a> <a href={''}>Documentation</a>
</td> </td>
<td> <td>
<a href={""}>Release Notes</a> <a href={''}>Release Notes</a>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -55,10 +53,10 @@ class Versions extends React.Component {
<tr> <tr>
<th>master</th> <th>master</th>
<td> <td>
<a href={""}>Documentation</a> <a href={''}>Documentation</a>
</td> </td>
<td> <td>
<a href={""}>Release Notes</a> <a href={''}>Release Notes</a>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -70,23 +68,22 @@ class Versions extends React.Component {
<tbody> <tbody>
{versions.map( {versions.map(
version => version =>
version !== latestVersion && version !== latestVersion && (
<tr> <tr>
<th> <th>{version}</th>
{version} <td>
</th> <a href={''}>Documentation</a>
<td> </td>
<a href={""}>Documentation</a> <td>
</td> <a href={''}>Release Notes</a>
<td> </td>
<a href={""}>Release Notes</a> </tr>
</td> )
</tr>
)} )}
</tbody> </tbody>
</table> </table>
<p> <p>
You can find past versions of this project{" "} You can find past versions of this project{' '}
<a href="https://github.com/"> on GitHub </a>. <a href="https://github.com/"> on GitHub </a>.
</p> </p>
</div> </div>

View file

@ -7,25 +7,25 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
require("babel-register")({ require('babel-register')({
babelrc: false, babelrc: false,
only: [__dirname, process.cwd() + "/core"], only: [__dirname, process.cwd() + '/core'],
plugins: [require("./server/translate-plugin.js")], plugins: [require('./server/translate-plugin.js')],
presets: ["react", "env"] presets: ['react', 'env'],
}); });
// initial check that required files are present // initial check that required files are present
const chalk = require("chalk"); const chalk = require('chalk');
const fs = require("fs"); const fs = require('fs');
const CWD = process.cwd(); const CWD = process.cwd();
if (!fs.existsSync(CWD + "/siteConfig.js")) { if (!fs.existsSync(CWD + '/siteConfig.js')) {
console.error( console.error(
chalk.red("Error: No siteConfig.js file found in website folder!") chalk.red('Error: No siteConfig.js file found in website folder!')
); );
process.exit(1); process.exit(1);
} }
// generate all static html files // generate all static html files
const generate = require("./server/generate.js"); const generate = require('./server/generate.js');
generate(); generate();

View file

@ -7,45 +7,45 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const chalk = require("chalk"); const chalk = require('chalk');
const commander = require("commander"); const commander = require('commander');
const fs = require("fs-extra"); const fs = require('fs-extra');
const glob = require("glob"); const glob = require('glob');
const path = require("path"); const path = require('path');
const CWD = process.cwd(); const CWD = process.cwd();
let feature; let feature;
commander commander
.arguments("[feature]") .arguments('[feature]')
.action(feat => { .action(feat => {
feature = feat; feature = feat;
}) })
.parse(process.argv); .parse(process.argv);
// add scripts to package.json file // add scripts to package.json file
if (fs.existsSync(CWD + "/package.json")) { if (fs.existsSync(CWD + '/package.json')) {
const packageContent = JSON.parse( const packageContent = JSON.parse(
fs.readFileSync(CWD + "/package.json", "utf8") fs.readFileSync(CWD + '/package.json', 'utf8')
); );
if (!packageContent.scripts) { if (!packageContent.scripts) {
packageContent.scripts = {}; packageContent.scripts = {};
} }
packageContent.scripts["start"] = "docusaurus-start"; packageContent.scripts['start'] = 'docusaurus-start';
packageContent.scripts["build"] = "docusaurus-build"; packageContent.scripts['build'] = 'docusaurus-build';
packageContent.scripts["publish-gh-pages"] = "docusaurus-publish"; packageContent.scripts['publish-gh-pages'] = 'docusaurus-publish';
packageContent.scripts["examples"] = "docusaurus-examples"; packageContent.scripts['examples'] = 'docusaurus-examples';
packageContent.scripts["write-translations"] = packageContent.scripts['write-translations'] =
"docusaurus-write-translations"; 'docusaurus-write-translations';
packageContent.scripts["version"] = "docusaurus-version"; packageContent.scripts['version'] = 'docusaurus-version';
packageContent.scripts["rename-version"] = "docusaurus-rename-version"; packageContent.scripts['rename-version'] = 'docusaurus-rename-version';
fs.writeFileSync( fs.writeFileSync(
CWD + "/package.json", CWD + '/package.json',
JSON.stringify(packageContent, null, 2) JSON.stringify(packageContent, null, 2)
); );
console.log( console.log(
`${chalk.green("Wrote docusaurus scripts to package.json file.")}\n` `${chalk.green('Wrote docusaurus scripts to package.json file.')}\n`
); );
} }
@ -56,48 +56,48 @@ let blogCreated = false;
let exampleSiteCreated = false; let exampleSiteCreated = false;
// handles cases where feature is "translations", "versions" or neither/not present // handles cases where feature is "translations", "versions" or neither/not present
if (feature === "translations") { if (feature === 'translations') {
// copy files for translations // copy files for translations
const folder = path.join(__dirname, "..", "examples", "translations"); const folder = path.join(__dirname, '..', 'examples', 'translations');
if (fs.existsSync(CWD + "/../crowdin.yaml")) { if (fs.existsSync(CWD + '/../crowdin.yaml')) {
console.log( console.log(
`${chalk.yellow("crowdin.yaml already exists")} in ${chalk.yellow( `${chalk.yellow('crowdin.yaml already exists')} in ${chalk.yellow(
outerFolder + "/" outerFolder + '/'
)}. Rename or remove the file to regenerate an example version.\n` )}. Rename or remove the file to regenerate an example version.\n`
); );
} else { } else {
fs.copySync(folder + "/crowdin.yaml", CWD + "/../crowdin.yaml"); fs.copySync(folder + '/crowdin.yaml', CWD + '/../crowdin.yaml');
exampleSiteCreated = true; exampleSiteCreated = true;
} }
let files = glob.sync(folder + "/**/*"); let files = glob.sync(folder + '/**/*');
files.forEach(file => { files.forEach(file => {
if (fs.lstatSync(file).isDirectory()) { if (fs.lstatSync(file).isDirectory()) {
return; return;
} }
if (path.basename(file) === "crowdin.yaml") { if (path.basename(file) === 'crowdin.yaml') {
return; return;
} }
const filePath = path.resolve(file).split(path.resolve(folder))[1]; const filePath = path.resolve(file).split(path.resolve(folder))[1];
try { try {
fs.copySync(file, CWD + filePath, { fs.copySync(file, CWD + filePath, {
overwrite: false, overwrite: false,
errorOnExist: true errorOnExist: true,
}); });
exampleSiteCreated = true; exampleSiteCreated = true;
} catch (e) { } catch (e) {
console.log( console.log(
`${chalk.yellow( `${chalk.yellow(
path.basename(filePath) + " already exists" path.basename(filePath) + ' already exists'
)} in ${chalk.yellow( )} in ${chalk.yellow(
"website" + filePath.split(path.basename(filePath))[0] 'website' + filePath.split(path.basename(filePath))[0]
)}. Rename or remove the file to regenerate an example version.\n` )}. Rename or remove the file to regenerate an example version.\n`
); );
} }
}); });
} else if (feature === "versions") { } else if (feature === 'versions') {
// copy files for versions // copy files for versions
const folder = path.join(__dirname, "..", "examples", "versions"); const folder = path.join(__dirname, '..', 'examples', 'versions');
let files = glob.sync(folder + "/**/*"); let files = glob.sync(folder + '/**/*');
files.forEach(file => { files.forEach(file => {
if (fs.lstatSync(file).isDirectory()) { if (fs.lstatSync(file).isDirectory()) {
return; return;
@ -106,76 +106,76 @@ if (feature === "translations") {
try { try {
fs.copySync(file, CWD + filePath, { fs.copySync(file, CWD + filePath, {
overwrite: false, overwrite: false,
errorOnExist: true errorOnExist: true,
}); });
exampleSiteCreated = true; exampleSiteCreated = true;
} catch (e) { } catch (e) {
console.log( console.log(
`${chalk.yellow( `${chalk.yellow(
path.basename(filePath) + " already exists" path.basename(filePath) + ' already exists'
)} in ${chalk.yellow( )} in ${chalk.yellow(
"website" + filePath.split(path.basename(filePath))[0] 'website' + filePath.split(path.basename(filePath))[0]
)}. Rename or remove the file to regenerate an example version.\n` )}. Rename or remove the file to regenerate an example version.\n`
); );
} }
}); });
} else { } else {
const folder = path.join(__dirname, "..", "examples", "basics"); const folder = path.join(__dirname, '..', 'examples', 'basics');
// copy docs examples // copy docs examples
if (fs.existsSync(CWD + "/../docs-examples-from-docusaurus")) { if (fs.existsSync(CWD + '/../docs-examples-from-docusaurus')) {
console.log( console.log(
`${chalk.yellow( `${chalk.yellow(
"Example docs already exist!" 'Example docs already exist!'
)} Rename or remove ${chalk.yellow( )} Rename or remove ${chalk.yellow(
outerFolder + "/docs-examples-from-docusaurus" outerFolder + '/docs-examples-from-docusaurus'
)} to regenerate example docs.\n` )} to regenerate example docs.\n`
); );
} else { } else {
fs.copySync( fs.copySync(
folder + "/docs-examples-from-docusaurus", folder + '/docs-examples-from-docusaurus',
CWD + "/../docs-examples-from-docusaurus" CWD + '/../docs-examples-from-docusaurus'
); );
exampleSiteCreated = true; exampleSiteCreated = true;
docsCreated = true; docsCreated = true;
} }
// copy blog examples // copy blog examples
if (fs.existsSync(CWD + "/blog-examples-from-docusaurus")) { if (fs.existsSync(CWD + '/blog-examples-from-docusaurus')) {
console.log( console.log(
`${chalk.yellow( `${chalk.yellow(
"Example blog posts already exist!" 'Example blog posts already exist!'
)} Rename or remove ${chalk.yellow( )} Rename or remove ${chalk.yellow(
outerFolder + "/website/blog-examples-from-docusaurus" outerFolder + '/website/blog-examples-from-docusaurus'
)} to regenerate example blog posts.\n` )} to regenerate example blog posts.\n`
); );
} else { } else {
fs.copySync( fs.copySync(
path.join(folder, "blog-examples-from-docusaurus"), path.join(folder, 'blog-examples-from-docusaurus'),
path.join(CWD, "blog-examples-from-docusaurus") path.join(CWD, 'blog-examples-from-docusaurus')
); );
exampleSiteCreated = true; exampleSiteCreated = true;
blogCreated = true; blogCreated = true;
} }
// copy .gitignore file // copy .gitignore file
if (fs.existsSync(CWD + "/.gitignore")) { if (fs.existsSync(CWD + '/.gitignore')) {
console.log( console.log(
`${chalk.yellow(".gitignore already exists")} in ${chalk.yellow( `${chalk.yellow('.gitignore already exists')} in ${chalk.yellow(
CWD CWD
)}. Rename or remove the file to regenerate an example version.\n` )}. Rename or remove the file to regenerate an example version.\n`
); );
} else { } else {
fs.copySync(path.join(folder, "gitignore"), path.join(CWD, ".gitignore")); fs.copySync(path.join(folder, 'gitignore'), path.join(CWD, '.gitignore'));
} }
// copy other files // copy other files
let files = glob.sync(folder + "/**/*"); let files = glob.sync(folder + '/**/*');
files.forEach(file => { files.forEach(file => {
if (fs.lstatSync(file).isDirectory()) { if (fs.lstatSync(file).isDirectory()) {
return; return;
} }
const containingFolder = path.basename(path.dirname(file)); const containingFolder = path.basename(path.dirname(file));
if ( if (
path.basename(file) === "gitignore" || path.basename(file) === 'gitignore' ||
containingFolder === "blog-examples-from-docusaurus" || containingFolder === 'blog-examples-from-docusaurus' ||
containingFolder === "docs-examples-from-docusaurus" containingFolder === 'docs-examples-from-docusaurus'
) { ) {
return; return;
} }
@ -183,15 +183,15 @@ if (feature === "translations") {
try { try {
fs.copySync(file, CWD + filePath, { fs.copySync(file, CWD + filePath, {
overwrite: false, overwrite: false,
errorOnExist: true errorOnExist: true,
}); });
exampleSiteCreated = true; exampleSiteCreated = true;
} catch (e) { } catch (e) {
console.log( console.log(
`${chalk.yellow( `${chalk.yellow(
path.basename(filePath) + " already exists" path.basename(filePath) + ' already exists'
)} in ${chalk.yellow( )} in ${chalk.yellow(
"website" + filePath.split(path.basename(filePath))[0] 'website' + filePath.split(path.basename(filePath))[0]
)}. Rename or remove the file to regenerate an example version.\n` )}. Rename or remove the file to regenerate an example version.\n`
); );
} }
@ -200,8 +200,8 @@ if (feature === "translations") {
if (exampleSiteCreated) { if (exampleSiteCreated) {
console.log( console.log(
`${chalk.green("Example website created")} in ${chalk.green( `${chalk.green('Example website created')} in ${chalk.green(
CWD + "/website" CWD + '/website'
)}\n` )}\n`
); );
} }
@ -209,9 +209,9 @@ if (exampleSiteCreated) {
if (docsCreated) { if (docsCreated) {
console.log( console.log(
`Rename ${chalk.yellow( `Rename ${chalk.yellow(
outerFolder + "/docs-examples-from-docusaurus" outerFolder + '/docs-examples-from-docusaurus'
)} to ${chalk.yellow( )} to ${chalk.yellow(
outerFolder + "/docs" outerFolder + '/docs'
)} to see the example docs on your site.\n` )} to see the example docs on your site.\n`
); );
} }
@ -219,9 +219,9 @@ if (docsCreated) {
if (blogCreated) { if (blogCreated) {
console.log( console.log(
`Rename ${chalk.yellow( `Rename ${chalk.yellow(
outerFolder + "/website/blog-examples-from-docusaurus" outerFolder + '/website/blog-examples-from-docusaurus'
)} to ${chalk.yellow( )} to ${chalk.yellow(
outerFolder + "/website/blog" outerFolder + '/website/blog'
)} to see the example blog posts on your site.\n` )} to see the example blog posts on your site.\n`
); );
} }

View file

@ -5,19 +5,19 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const BlogPost = require("./BlogPost.js"); const BlogPost = require('./BlogPost.js');
const BlogSidebar = require("./BlogSidebar.js"); const BlogSidebar = require('./BlogSidebar.js');
const Container = require("./Container.js"); const Container = require('./Container.js');
const MetadataBlog = require("./MetadataBlog.js"); const MetadataBlog = require('./MetadataBlog.js');
const React = require("react"); const React = require('react');
const Site = require("./Site.js"); const Site = require('./Site.js');
// used to generate entire blog pages, i.e. collection of truncated blog posts // used to generate entire blog pages, i.e. collection of truncated blog posts
class BlogPageLayout extends React.Component { class BlogPageLayout extends React.Component {
getPageURL(page) { getPageURL(page) {
let url = this.props.config.baseUrl + "blog/"; let url = this.props.config.baseUrl + 'blog/';
if (page > 0) { if (page > 0) {
url += "page" + (page + 1) + "/"; url += 'page' + (page + 1) + '/';
} }
return url; return url;
} }
@ -34,20 +34,19 @@ class BlogPageLayout extends React.Component {
/> />
<Container className="mainContainer documentContainer postContainer blogContainer"> <Container className="mainContainer documentContainer postContainer blogContainer">
<div className="posts"> <div className="posts">
{MetadataBlog.slice( {MetadataBlog.slice(page * perPage, (page + 1) * perPage).map(
page * perPage, post => {
(page + 1) * perPage return (
).map(post => { <BlogPost
return ( post={post}
<BlogPost content={post.content}
post={post} truncate={true}
content={post.content} key={post.path + post.title}
truncate={true} config={this.props.config}
key={post.path + post.title} />
config={this.props.config} );
/> }
); )}
})}
<div className="docs-prevnext"> <div className="docs-prevnext">
{page > 0 && ( {page > 0 && (
<a className="docs-prev" href={this.getPageURL(page - 1)}> <a className="docs-prev" href={this.getPageURL(page - 1)}>

View file

@ -5,27 +5,27 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const MarkdownBlock = require("./MarkdownBlock.js"); const MarkdownBlock = require('./MarkdownBlock.js');
const React = require("react"); const React = require('react');
// inner blog component for the article itself, without sidebar/header/footer // inner blog component for the article itself, without sidebar/header/footer
class BlogPost extends React.Component { class BlogPost extends React.Component {
renderContent() { renderContent() {
let content = this.props.content; let content = this.props.content;
let hasSplit = false; let hasSplit = false;
if (content.split("<!--truncate-->").length > 1) { if (content.split('<!--truncate-->').length > 1) {
hasSplit = ( hasSplit = (
<div className="read-more"> <div className="read-more">
<a <a
className="button" className="button"
href={this.props.config.baseUrl + "blog/" + this.props.post.path}> href={this.props.config.baseUrl + 'blog/' + this.props.post.path}>
Read More Read More
</a> </a>
</div> </div>
); );
} }
if (this.props.truncate) { if (this.props.truncate) {
content = content.split("<!--truncate-->")[0]; content = content.split('<!--truncate-->')[0];
return ( return (
<article className="post-content"> <article className="post-content">
<MarkdownBlock>{content}</MarkdownBlock> <MarkdownBlock>{content}</MarkdownBlock>
@ -39,17 +39,17 @@ class BlogPost extends React.Component {
renderAuthorPhoto() { renderAuthorPhoto() {
const post = this.props.post; const post = this.props.post;
const className = const className =
"authorPhoto" + 'authorPhoto' +
(post.author && post.authorTitle ? " authorPhoto-big" : ""); (post.author && post.authorTitle ? ' authorPhoto-big' : '');
if (post.authorFBID) { if (post.authorFBID) {
return ( return (
<div className={className}> <div className={className}>
<a href={post.authorURL} target="_blank"> <a href={post.authorURL} target="_blank">
<img <img
src={ src={
"https://graph.facebook.com/" + 'https://graph.facebook.com/' +
post.authorFBID + post.authorFBID +
"/picture/?height=200&width=200" '/picture/?height=200&width=200'
} }
/> />
</a> </a>
@ -72,7 +72,7 @@ class BlogPost extends React.Component {
const post = this.props.post; const post = this.props.post;
return ( return (
<h1> <h1>
<a href={this.props.config.baseUrl + "blog/" + post.path}> <a href={this.props.config.baseUrl + 'blog/' + post.path}>
{post.title} {post.title}
</a> </a>
</h1> </h1>
@ -85,18 +85,18 @@ class BlogPost extends React.Component {
// Because JavaScript sucks at date handling :( // Because JavaScript sucks at date handling :(
const year = match[1]; const year = match[1];
const month = [ const month = [
"January", 'January',
"February", 'February',
"March", 'March',
"April", 'April',
"May", 'May',
"June", 'June',
"July", 'July',
"August", 'August',
"September", 'September',
"October", 'October',
"November", 'November',
"December" 'December',
][parseInt(match[2], 10) - 1]; ][parseInt(match[2], 10) - 1];
const day = parseInt(match[3], 10); const day = parseInt(match[3], 10);

View file

@ -5,31 +5,44 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
const BlogPost = require("./BlogPost.js"); const BlogPost = require('./BlogPost.js');
const BlogSidebar = require("./BlogSidebar.js"); const BlogSidebar = require('./BlogSidebar.js');
const Container = require("./Container.js"); const Container = require('./Container.js');
const Site = require("./Site.js"); const Site = require('./Site.js');
// used for entire blog posts, i.e., each written blog article with sidebar with site header/footer // used for entire blog posts, i.e., each written blog article with sidebar with site header/footer
class BlogPostLayout extends React.Component { class BlogPostLayout extends React.Component {
renderSocialButtons() { renderSocialButtons() {
const post = this.props.metadata; const post = this.props.metadata;
const fbLike = this.props.config.facebookAppId ? const fbLike = this.props.config.facebookAppId ? (
<div <div
className="fb-like" className="fb-like"
data-layout="standard" data-layout="standard"
data-share="true" data-share="true"
data-width="225" data-width="225"
data-show-faces="false"> data-show-faces="false"
</div> />
: null; ) : null;
const twitterShare = this.props.config.twitter ? const twitterShare = this.props.config.twitter ? (
<a href="https://twitter.com/share" className="twitter-share-button" data-text={post.title} data-url={this.props.config.url + this.props.config.baseUrl + "blog/" + post.path} data-related={this.props.config.twitter} data-via={post.authorTwitter} data-show-count="false">Tweet</a> <a
: null; href="https://twitter.com/share"
className="twitter-share-button"
data-text={post.title}
data-url={
this.props.config.url +
this.props.config.baseUrl +
'blog/' +
post.path
}
data-related={this.props.config.twitter}
data-via={post.authorTwitter}
data-show-count="false">
Tweet
</a>
) : null;
if (!fbLike && !twitterShare) { if (!fbLike && !twitterShare) {
return; return;
@ -51,15 +64,14 @@ class BlogPostLayout extends React.Component {
return ( return (
<Site <Site
className="sideNavVisible" className="sideNavVisible"
url={"blog/" + this.props.metadata.path} url={'blog/' + this.props.metadata.path}
title={this.props.metadata.title} title={this.props.metadata.title}
language={"en"} language={'en'}
description={this.props.children.trim().split("\n")[0]} description={this.props.children.trim().split('\n')[0]}
config={this.props.config} config={this.props.config}>
>
<div className="docMainWrapper wrapper"> <div className="docMainWrapper wrapper">
<BlogSidebar <BlogSidebar
language={"en"} language={'en'}
current={this.props.metadata} current={this.props.metadata}
config={this.props.config} config={this.props.config}
/> />
@ -68,16 +80,13 @@ class BlogPostLayout extends React.Component {
<BlogPost <BlogPost
post={this.props.metadata} post={this.props.metadata}
content={this.props.children} content={this.props.children}
language={"en"} language={'en'}
config={this.props.config} config={this.props.config}
/> />
{this.renderSocialButtons()} {this.renderSocialButtons()}
</div> </div>
<div className="blog-recent"> <div className="blog-recent">
<a <a className="button" href={this.props.config.baseUrl + 'blog'}>
className="button"
href={this.props.config.baseUrl + "blog"}
>
Recent Posts Recent Posts
</a> </a>
</div> </div>

View file

@ -5,30 +5,30 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
const Container = require("./Container.js"); const Container = require('./Container.js');
const SideNav = require("./nav/SideNav.js"); const SideNav = require('./nav/SideNav.js');
const MetadataBlog = require("./MetadataBlog.js"); const MetadataBlog = require('./MetadataBlog.js');
class BlogSidebar extends React.Component { class BlogSidebar extends React.Component {
render() { render() {
const contents = [ const contents = [
{ {
name: "Recent Posts", name: 'Recent Posts',
links: MetadataBlog.slice(0, 5) links: MetadataBlog.slice(0, 5),
} },
]; ];
const title = this.props.current && this.props.current.title; const title = this.props.current && this.props.current.title;
const current = { const current = {
id: title || "", id: title || '',
category: "Recent Posts" category: 'Recent Posts',
}; };
return ( return (
<Container className="docsNavContainer" id="docsNav" wrapper={false}> <Container className="docsNavContainer" id="docsNav" wrapper={false}>
<SideNav <SideNav
language={this.props.language} language={this.props.language}
root={this.props.config.baseUrl + "blog/"} root={this.props.config.baseUrl + 'blog/'}
title="Blog" title="Blog"
contents={contents} contents={contents}
current={current} current={current}

View file

@ -5,13 +5,13 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const MarkdownBlock = require("./MarkdownBlock.js"); const MarkdownBlock = require('./MarkdownBlock.js');
const Container = require("./Container.js"); const Container = require('./Container.js');
const GridBlock = require("./GridBlock.js"); const GridBlock = require('./GridBlock.js');
// A collection of components to provide to users // A collection of components to provide to users
module.exports = { module.exports = {
MarkdownBlock: MarkdownBlock, MarkdownBlock: MarkdownBlock,
Container: Container, Container: Container,
GridBlock: GridBlock GridBlock: GridBlock,
}; };

View file

@ -5,29 +5,25 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
const classNames = require("classnames"); const classNames = require('classnames');
class Container extends React.Component { class Container extends React.Component {
render() { render() {
const containerClasses = classNames("container", this.props.className, { const containerClasses = classNames('container', this.props.className, {
darkBackground: this.props.background === "dark", darkBackground: this.props.background === 'dark',
highlightBackground: this.props.background === "highlight", highlightBackground: this.props.background === 'highlight',
lightBackground: this.props.background === "light", lightBackground: this.props.background === 'light',
paddingAll: this.props.padding.indexOf("all") >= 0, paddingAll: this.props.padding.indexOf('all') >= 0,
paddingBottom: this.props.padding.indexOf("bottom") >= 0, paddingBottom: this.props.padding.indexOf('bottom') >= 0,
paddingLeft: this.props.padding.indexOf("left") >= 0, paddingLeft: this.props.padding.indexOf('left') >= 0,
paddingRight: this.props.padding.indexOf("right") >= 0, paddingRight: this.props.padding.indexOf('right') >= 0,
paddingTop: this.props.padding.indexOf("top") >= 0 paddingTop: this.props.padding.indexOf('top') >= 0,
}); });
let wrappedChildren; let wrappedChildren;
if (this.props.wrapper) { if (this.props.wrapper) {
wrappedChildren = ( wrappedChildren = <div className="wrapper">{this.props.children}</div>;
<div className="wrapper">
{this.props.children}
</div>
);
} else { } else {
wrappedChildren = this.props.children; wrappedChildren = this.props.children;
} }
@ -40,9 +36,9 @@ class Container extends React.Component {
} }
Container.defaultProps = { Container.defaultProps = {
background: "transparent", background: 'transparent',
padding: [], padding: [],
wrapper: true wrapper: true,
}; };
module.exports = Container; module.exports = Container;

View file

@ -5,16 +5,16 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
const MarkdownBlock = require("./MarkdownBlock.js"); const MarkdownBlock = require('./MarkdownBlock.js');
const translate = require("../server/translate.js").translate; const translate = require('../server/translate.js').translate;
const editThisDoc = translate( const editThisDoc = translate(
"Edit this Doc|recruitment message asking to edit the doc source" 'Edit this Doc|recruitment message asking to edit the doc source'
); );
const translateThisDoc = translate( const translateThisDoc = translate(
"Translate this Doc|recruitment message asking to translate the docs" 'Translate this Doc|recruitment message asking to translate the docs'
); );
// inner doc component for article itself // inner doc component for article itself
@ -29,14 +29,14 @@ class Doc extends React.Component {
{editThisDoc} {editThisDoc}
</a> </a>
); );
if (this.props.language != "en") { if (this.props.language != 'en') {
editLink = !this.props.version && editLink = !this.props.version &&
this.props.config.translationRecruitingLink && ( this.props.config.translationRecruitingLink && (
<a <a
className="edit-page-link button" className="edit-page-link button"
href={ href={
this.props.config.translationRecruitingLink + this.props.config.translationRecruitingLink +
"/" + '/' +
this.props.language this.props.language
} }
target="_blank"> target="_blank">

View file

@ -5,12 +5,12 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
const Container = require("./Container.js"); const Container = require('./Container.js');
const Doc = require("./Doc.js"); const Doc = require('./Doc.js');
const DocsSidebar = require("./DocsSidebar.js"); const DocsSidebar = require('./DocsSidebar.js');
const Site = require("./Site.js"); const Site = require('./Site.js');
const translation = require("../server/translation.js"); const translation = require('../server/translation.js');
// component used to generate whole webpage for docs, including sidebar/header/footer // component used to generate whole webpage for docs, including sidebar/header/footer
class DocsLayout extends React.Component { class DocsLayout extends React.Component {
@ -28,12 +28,12 @@ class DocsLayout extends React.Component {
className="sideNavVisible" className="sideNavVisible"
title={ title={
i18n i18n
? translation[this.props.metadata.language]["localized-strings"][ ? translation[this.props.metadata.language]['localized-strings'][
this.props.metadata.localized_id this.props.metadata.localized_id
] || this.props.metadata.title ] || this.props.metadata.title
: this.props.metadata.title : this.props.metadata.title
} }
description={content.trim().split("\n")[0]} description={content.trim().split('\n')[0]}
language={metadata.language} language={metadata.language}
version={metadata.version}> version={metadata.version}>
<div className="docMainWrapper wrapper"> <div className="docMainWrapper wrapper">
@ -47,7 +47,7 @@ class DocsLayout extends React.Component {
title={ title={
i18n i18n
? translation[this.props.metadata.language][ ? translation[this.props.metadata.language][
"localized-strings" 'localized-strings'
][this.props.metadata.localized_id] || ][this.props.metadata.localized_id] ||
this.props.metadata.title this.props.metadata.title
: this.props.metadata.title : this.props.metadata.title
@ -58,34 +58,32 @@ class DocsLayout extends React.Component {
{metadata.previous_id && ( {metadata.previous_id && (
<a <a
className="docs-prev button" className="docs-prev button"
href={metadata.previous_id + ".html"}> href={metadata.previous_id + '.html'}>
{" "} {' '}
{i18n {i18n
? translation[this.props.metadata.language][ ? translation[this.props.metadata.language][
"localized-strings" 'localized-strings'
][metadata.previous_id] || ][metadata.previous_id] ||
translation[this.props.metadata.language][ translation[this.props.metadata.language][
"localized-strings" 'localized-strings'
]["previous"] || ]['previous'] ||
"Previous" 'Previous'
: metadata.previous_title || "Previous" : metadata.previous_title || 'Previous'}
}
</a> </a>
)} )}
{metadata.next_id && ( {metadata.next_id && (
<a <a
className="docs-next button" className="docs-next button"
href={metadata.next_id + ".html"}> href={metadata.next_id + '.html'}>
{i18n {i18n
? translation[this.props.metadata.language][ ? translation[this.props.metadata.language][
"localized-strings" 'localized-strings'
][metadata.next_id] || ][metadata.next_id] ||
translation[this.props.metadata.language][ translation[this.props.metadata.language][
"localized-strings" 'localized-strings'
]["next"] || ]['next'] ||
"Next" 'Next'
: metadata.next_title || "Next" : metadata.next_title || 'Next'}{' '}
}{" "}
</a> </a>
)} )}

View file

@ -5,12 +5,12 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const Metadata = require("./metadata.js"); const Metadata = require('./metadata.js');
const React = require("react"); const React = require('react');
const Container = require("./Container.js"); const Container = require('./Container.js');
const SideNav = require("./nav/SideNav.js"); const SideNav = require('./nav/SideNav.js');
const siteConfig = require(process.cwd() + "/siteConfig.js"); const siteConfig = require(process.cwd() + '/siteConfig.js');
const readCategories = require("../server/readCategories.js"); const readCategories = require('../server/readCategories.js');
class DocsSidebar extends React.Component { class DocsSidebar extends React.Component {
render() { render() {

View file

@ -5,32 +5,32 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
const classNames = require("classnames"); const classNames = require('classnames');
const MarkdownBlock = require("./MarkdownBlock.js"); const MarkdownBlock = require('./MarkdownBlock.js');
class GridBlock extends React.Component { class GridBlock extends React.Component {
renderBlock(block) { renderBlock(block) {
const blockClasses = classNames("blockElement", this.props.className, { const blockClasses = classNames('blockElement', this.props.className, {
alignCenter: this.props.align === "center", alignCenter: this.props.align === 'center',
alignRight: this.props.align === "right", alignRight: this.props.align === 'right',
fourByGridBlock: this.props.layout === "fourColumn", fourByGridBlock: this.props.layout === 'fourColumn',
imageAlignBottom: block.image && block.imageAlign === "bottom", imageAlignBottom: block.image && block.imageAlign === 'bottom',
imageAlignSide: imageAlignSide:
block.image && block.image &&
(block.imageAlign === "left" || block.imageAlign === "right"), (block.imageAlign === 'left' || block.imageAlign === 'right'),
imageAlignTop: block.image && block.imageAlign === "top", imageAlignTop: block.image && block.imageAlign === 'top',
threeByGridBlock: this.props.layout === "threeColumn", threeByGridBlock: this.props.layout === 'threeColumn',
twoByGridBlock: this.props.layout === "twoColumn" twoByGridBlock: this.props.layout === 'twoColumn',
}); });
const topLeftImage = const topLeftImage =
(block.imageAlign === "top" || block.imageAlign === "left") && (block.imageAlign === 'top' || block.imageAlign === 'left') &&
this.renderBlockImage(block.image, block.imageLink); this.renderBlockImage(block.image, block.imageLink);
const bottomRightImage = const bottomRightImage =
(block.imageAlign === "bottom" || block.imageAlign === "right") && (block.imageAlign === 'bottom' || block.imageAlign === 'right') &&
this.renderBlockImage(block.image, block.imageLink); this.renderBlockImage(block.image, block.imageLink);
return ( return (
@ -38,9 +38,7 @@ class GridBlock extends React.Component {
{topLeftImage} {topLeftImage}
<div className="blockContent"> <div className="blockContent">
{this.renderBlockTitle(block.title)} {this.renderBlockTitle(block.title)}
<MarkdownBlock> <MarkdownBlock>{block.content}</MarkdownBlock>
{block.content}
</MarkdownBlock>
</div> </div>
{bottomRightImage} {bottomRightImage}
</div> </div>
@ -73,9 +71,7 @@ class GridBlock extends React.Component {
if (title) { if (title) {
return ( return (
<h2> <h2>
<MarkdownBlock> <MarkdownBlock>{title}</MarkdownBlock>
{title}
</MarkdownBlock>
</h2> </h2>
); );
} else { } else {
@ -93,10 +89,10 @@ class GridBlock extends React.Component {
} }
GridBlock.defaultProps = { GridBlock.defaultProps = {
align: "left", align: 'left',
contents: [], contents: [],
imagealign: "top", imagealign: 'top',
layout: "twoColumn" layout: 'twoColumn',
}; };
module.exports = GridBlock; module.exports = GridBlock;

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
// html head for each page // html head for each page
class Head extends React.Component { class Head extends React.Component {
@ -17,8 +17,10 @@ class Head extends React.Component {
}); });
const highlightDefaultVersion = '9.12.0'; const highlightDefaultVersion = '9.12.0';
const highlightConfig = this.props.config.highlight const highlightConfig = this.props.config.highlight || {
|| { version: highlightDefaultVersion, theme: 'default' }; version: highlightDefaultVersion,
theme: 'default',
};
const highlightVersion = highlightConfig.version || highlightDefaultVersion; const highlightVersion = highlightConfig.version || highlightDefaultVersion;
const highlightTheme = highlightConfig.theme || 'default'; const highlightTheme = highlightConfig.theme || 'default';
@ -43,7 +45,7 @@ class Head extends React.Component {
{this.props.redirect && ( {this.props.redirect && (
<meta <meta
http-equiv="refresh" http-equiv="refresh"
content={"0; URL=" + this.props.redirect} content={'0; URL=' + this.props.redirect}
/> />
)} )}
<link <link
@ -58,45 +60,47 @@ class Head extends React.Component {
)} )}
<link <link
rel="stylesheet" rel="stylesheet"
href={`//cdnjs.cloudflare.com/ajax/libs/highlight.js/${highlightVersion}/styles/${highlightTheme}.min.css`} href={`//cdnjs.cloudflare.com/ajax/libs/highlight.js/${
highlightVersion
}/styles/${highlightTheme}.min.css`}
/> />
{hasBlog && ( {hasBlog && (
<link <link
rel="alternate" rel="alternate"
type="application/atom+xml" type="application/atom+xml"
href={this.props.config.url + "/blog/atom.xml"} href={this.props.config.url + '/blog/atom.xml'}
title={this.props.config.title + " Blog ATOM Feed"} title={this.props.config.title + ' Blog ATOM Feed'}
/> />
)} )}
{hasBlog && ( {hasBlog && (
<link <link
rel="alternate" rel="alternate"
type="application/rss+xml" type="application/rss+xml"
href={this.props.config.url + "/blog/feed.xml"} href={this.props.config.url + '/blog/feed.xml'}
title={this.props.config.title + " Blog RSS Feed"} title={this.props.config.title + ' Blog RSS Feed'}
/> />
)} )}
{/* External resources */} {/* External resources */}
{this.props.config.stylesheets && this.props.config.stylesheets.map(function(source) { {this.props.config.stylesheets &&
return ( this.props.config.stylesheets.map(function(source) {
<link rel="stylesheet" href={source} /> return <link rel="stylesheet" href={source} />;
); })}
})} {this.props.config.scripts &&
{this.props.config.scripts && this.props.config.scripts.map(function(source, idx) { this.props.config.scripts.map(function(source, idx) {
return ( return (
<script <script
type="text/javascript" type="text/javascript"
key={"script" + idx} key={'script' + idx}
src={source} src={source}
/> />
); );
})} })}
{/* Site defined code. Keep these at the end to avoid overriding. */} {/* Site defined code. Keep these at the end to avoid overriding. */}
<link <link
rel="stylesheet" rel="stylesheet"
href={this.props.config.baseUrl + "css/main.css"} href={this.props.config.baseUrl + 'css/main.css'}
/> />
</head> </head>
); );

View file

@ -5,19 +5,19 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
const toSlug = require("./toSlug.js"); const toSlug = require('./toSlug.js');
class Header extends React.Component { class Header extends React.Component {
render() { render() {
const slug = toSlug(this.props.toSlug || this.props.children); const slug = toSlug(this.props.toSlug || this.props.children);
const Heading = "h" + this.props.level; const Heading = 'h' + this.props.level;
return ( return (
<Heading {...this.props}> <Heading {...this.props}>
<a className="anchor" name={slug} /> <a className="anchor" name={slug} />
{this.props.children}{" "} {this.props.children}{' '}
<a className="hash-link" href={"#" + slug}> <a className="hash-link" href={'#' + slug}>
# #
</a> </a>
</Heading> </Heading>

View file

@ -14,11 +14,8 @@ const Remarkable = require('./Remarkable');
class MarkdownBlock extends React.Component { class MarkdownBlock extends React.Component {
render() { render() {
return ( return <Remarkable source={this.props.children} />;
<Remarkable source={this.props.children} />
);
} }
} }
module.exports = MarkdownBlock; module.exports = MarkdownBlock;

View file

@ -5,10 +5,10 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
const fs = require("fs"); const fs = require('fs');
const Head = require("./Head.js"); const Head = require('./Head.js');
const translation = require("../server/translation.js"); const translation = require('../server/translation.js');
const CWD = process.cwd(); const CWD = process.cwd();
@ -16,24 +16,24 @@ const CWD = process.cwd();
class Redirect extends React.Component { class Redirect extends React.Component {
render() { render() {
const tagline = translation[this.props.language] const tagline = translation[this.props.language]
? translation[this.props.language]["localized-strings"].tagline ? translation[this.props.language]['localized-strings'].tagline
: this.props.config.tagline; : this.props.config.tagline;
const title = this.props.title const title = this.props.title
? this.props.title + " · " + this.props.config.title ? this.props.title + ' · ' + this.props.config.title
: (!this.props.config.disableTitleTagline && : (!this.props.config.disableTitleTagline &&
this.props.config.title + " · " + tagline) || this.props.config.title + ' · ' + tagline) ||
this.props.config.title; this.props.config.title;
const description = this.props.description || tagline; const description = this.props.description || tagline;
const url = const url =
this.props.config.url + this.props.config.url +
this.props.config.baseUrl + this.props.config.baseUrl +
(this.props.url || "index.html"); (this.props.url || 'index.html');
let latestVersion; let latestVersion;
const redirect = this.props.redirect || false; const redirect = this.props.redirect || false;
if (fs.existsSync(CWD + "/versions.json")) { if (fs.existsSync(CWD + '/versions.json')) {
latestVersion = require(CWD + "/versions.json")[0]; latestVersion = require(CWD + '/versions.json')[0];
} }
return ( return (
<html> <html>
@ -51,7 +51,7 @@ class Redirect extends React.Component {
<!-- <!--
window.location.href = "${this.props.redirect}"; window.location.href = "${this.props.redirect}";
// --> // -->
` `,
}} }}
/> />
</body> </body>

View file

@ -1,9 +1,9 @@
'use strict'; 'use strict';
const React = require('react'); const React = require('react');
const hljs = require('highlight.js') const hljs = require('highlight.js');
const Markdown = require('remarkable'); const Markdown = require('remarkable');
const toSlug = require("./toSlug.js"); const toSlug = require('./toSlug.js');
const CWD = process.cwd(); const CWD = process.cwd();
@ -12,22 +12,38 @@ const CWD = process.cwd();
*/ */
function anchors(md) { function anchors(md) {
md.renderer.rules.heading_open = function(tokens, idx /*, options, env */) { md.renderer.rules.heading_open = function(tokens, idx /*, options, env */) {
const textToken = tokens[idx+1]; const textToken = tokens[idx + 1];
return '<h' + tokens[idx].hLevel + '><a class="anchor" aria-hidden="true" name="' + toSlug(textToken.content) + '"></a><a href="#' + toSlug(textToken.content) + '" aria-hidden="true" class="hash-link" ><svg aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>'; return (
'<h' +
tokens[idx].hLevel +
'><a class="anchor" aria-hidden="true" name="' +
toSlug(textToken.content) +
'"></a><a href="#' +
toSlug(textToken.content) +
'" aria-hidden="true" class="hash-link" ><svg aria-hidden="true" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path fill-rule="evenodd" d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>'
);
}; };
} }
class Remarkable extends React.Component { class Remarkable extends React.Component {
content() { content() {
if (this.props.source) { if (this.props.source) {
return <span dangerouslySetInnerHTML={{ __html: this.renderMarkdown(this.props.source) }} />; return (
} <span
else { dangerouslySetInnerHTML={{
__html: this.renderMarkdown(this.props.source),
}}
/>
);
} else {
return React.Children.map(this.props.children, child => { return React.Children.map(this.props.children, child => {
if (typeof child === 'string') { if (typeof child === 'string') {
return <span dangerouslySetInnerHTML={{ __html: this.renderMarkdown(child) }} />; return (
} <span
else { dangerouslySetInnerHTML={{__html: this.renderMarkdown(child)}}
/>
);
} else {
return child; return child;
} }
}); });
@ -36,14 +52,15 @@ class Remarkable extends React.Component {
renderMarkdown(source) { renderMarkdown(source) {
if (!this.md) { if (!this.md) {
const siteConfig = require(CWD + "/siteConfig.js"); const siteConfig = require(CWD + '/siteConfig.js');
this.md = new Markdown({ this.md = new Markdown({
// Highlight.js expects hljs css classes on the code element. // Highlight.js expects hljs css classes on the code element.
// This results in <pre><code class="hljs css javascript"> // This results in <pre><code class="hljs css javascript">
langPrefix: 'hljs css ', langPrefix: 'hljs css ',
highlight: function (str, lang) { highlight: function(str, lang) {
lang = lang || (siteConfig.highlight && siteConfig.highlight.defaultLang); lang =
lang || (siteConfig.highlight && siteConfig.highlight.defaultLang);
if (lang && hljs.getLanguage(lang)) { if (lang && hljs.getLanguage(lang)) {
try { try {
return hljs.highlight(lang, str).value; return hljs.highlight(lang, str).value;
@ -69,23 +86,18 @@ class Remarkable extends React.Component {
this.md.use(plugin); this.md.use(plugin);
}, this); }, this);
} }
} }
const html = this.md.render(source); const html = this.md.render(source);
// Ensure fenced code blocks use Highlight.js hljs class // Ensure fenced code blocks use Highlight.js hljs class
// https://github.com/jonschlinkert/remarkable/issues/224 // https://github.com/jonschlinkert/remarkable/issues/224
return html.replace(/<pre><code>/g,'<pre><code class="hljs">'); return html.replace(/<pre><code>/g, '<pre><code class="hljs">');
} }
render() { render() {
var Container = this.props.container; var Container = this.props.container;
return ( return <Container>{this.content()}</Container>;
<Container>
{this.content()}
</Container>
);
} }
} }

View file

@ -5,12 +5,12 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
const fs = require("fs"); const fs = require('fs');
const HeaderNav = require("./nav/HeaderNav.js"); const HeaderNav = require('./nav/HeaderNav.js');
const Head = require("./Head.js"); const Head = require('./Head.js');
const Footer = require(process.cwd() + "/core/Footer.js"); const Footer = require(process.cwd() + '/core/Footer.js');
const translation = require("../server/translation.js"); const translation = require('../server/translation.js');
const CWD = process.cwd(); const CWD = process.cwd();
@ -18,28 +18,28 @@ const CWD = process.cwd();
class Site extends React.Component { class Site extends React.Component {
render() { render() {
const tagline = translation[this.props.language] const tagline = translation[this.props.language]
? translation[this.props.language]["localized-strings"].tagline ? translation[this.props.language]['localized-strings'].tagline
: this.props.config.tagline; : this.props.config.tagline;
const title = this.props.title const title = this.props.title
? this.props.title + " · " + this.props.config.title ? this.props.title + ' · ' + this.props.config.title
: (!this.props.config.disableTitleTagline && : (!this.props.config.disableTitleTagline &&
this.props.config.title + " · " + tagline) || this.props.config.title + ' · ' + tagline) ||
this.props.config.title; this.props.config.title;
const description = this.props.description || tagline; const description = this.props.description || tagline;
const url = const url =
this.props.config.url + this.props.config.url +
this.props.config.baseUrl + this.props.config.baseUrl +
(this.props.url || "index.html"); (this.props.url || 'index.html');
let latestVersion; let latestVersion;
const highlightDefaultVersion = "9.12.0"; const highlightDefaultVersion = '9.12.0';
const highlightConfig = this.props.config.highlight || { const highlightConfig = this.props.config.highlight || {
version: highlightDefaultVersion, version: highlightDefaultVersion,
theme: "default" theme: 'default',
}; };
const highlightVersion = highlightConfig.version || highlightDefaultVersion; const highlightVersion = highlightConfig.version || highlightDefaultVersion;
if (fs.existsSync(CWD + "/versions.json")) { if (fs.existsSync(CWD + '/versions.json')) {
latestVersion = require(CWD + "/versions.json")[0]; latestVersion = require(CWD + '/versions.json')[0];
} }
return ( return (
<html> <html>
@ -78,24 +78,24 @@ class Site extends React.Component {
ga('create', '${this.props.config.gaTrackingId}', 'auto'); ga('create', '${this.props.config.gaTrackingId}', 'auto');
ga('send', 'pageview'); ga('send', 'pageview');
` `,
}} }}
/> />
)} )}
{this.props.config.facebookAppId && ( {this.props.config.facebookAppId && (
<script <script
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
__html: `window.fbAsyncInit = function() {FB.init({appId:'${this __html: `window.fbAsyncInit = function() {FB.init({appId:'${
.props.config this.props.config.facebookAppId
.facebookAppId}',xfbml:true,version:'v2.7'});};(function(d, s, id){var js, fjs = d.getElementsByTagName(s)[0];if (d.getElementById(id)) {return;}js = d.createElement(s); js.id = id;js.src = '//connect.facebook.net/en_US/sdk.js';fjs.parentNode.insertBefore(js, fjs);}(document, 'script','facebook-jssdk')); }',xfbml:true,version:'v2.7'});};(function(d, s, id){var js, fjs = d.getElementsByTagName(s)[0];if (d.getElementById(id)) {return;}js = d.createElement(s); js.id = id;js.src = '//connect.facebook.net/en_US/sdk.js';fjs.parentNode.insertBefore(js, fjs);}(document, 'script','facebook-jssdk'));
` `,
}} }}
/> />
)} )}
{this.props.config.twitter && ( {this.props.config.twitter && (
<script <script
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
__html: `window.twttr=(function(d,s, id){var js,fjs=d.getElementsByTagName(s)[0],t=window.twttr||{};if(d.getElementById(id))return t;js=d.createElement(s);js.id=id;js.src='https://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js, fjs);t._e = [];t.ready = function(f) {t._e.push(f);};return t;}(document, 'script', 'twitter-wjs'));` __html: `window.twttr=(function(d,s, id){var js,fjs=d.getElementsByTagName(s)[0],t=window.twttr||{};if(d.getElementById(id))return t;js=d.createElement(s);js.id=id;js.src='https://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js, fjs);t._e = [];t.ready = function(f) {t._e.push(f);};return t;}(document, 'script', 'twitter-wjs'));`,
}} }}
/> />
)} )}
@ -111,10 +111,10 @@ class Site extends React.Component {
algoliaOptions: ${JSON.stringify( algoliaOptions: ${JSON.stringify(
this.props.config.algolia.algoliaOptions this.props.config.algolia.algoliaOptions
) )
.replace("VERSION", this.props.version || latestVersion) .replace('VERSION', this.props.version || latestVersion)
.replace("LANGUAGE", this.props.language)} .replace('LANGUAGE', this.props.language)}
}); });
` `,
}} }}
/> />
) : ( ) : (
@ -126,7 +126,7 @@ class Site extends React.Component {
indexName: '${this.props.config.algolia.indexName}', indexName: '${this.props.config.algolia.indexName}',
inputSelector: '#search_input_react' inputSelector: '#search_input_react'
}); });
` `,
}} }}
/> />
))} ))}

View file

@ -7,35 +7,35 @@
const CWD = process.cwd(); const CWD = process.cwd();
const React = require("react"); const React = require('react');
const fs = require("fs"); const fs = require('fs');
const siteConfig = require(CWD + "/siteConfig.js"); const siteConfig = require(CWD + '/siteConfig.js');
const translation = require("../../server/translation.js"); const translation = require('../../server/translation.js');
const translate = require("../../server/translate.js").translate; const translate = require('../../server/translate.js').translate;
const setLanguage = require("../../server/translate.js").setLanguage; const setLanguage = require('../../server/translate.js').setLanguage;
const ENABLE_TRANSLATION = fs.existsSync(CWD + "/languages.js"); const ENABLE_TRANSLATION = fs.existsSync(CWD + '/languages.js');
const ENABLE_VERSIONING = fs.existsSync(CWD + "/versions.json"); const ENABLE_VERSIONING = fs.existsSync(CWD + '/versions.json');
let versions; let versions;
if (ENABLE_VERSIONING) { if (ENABLE_VERSIONING) {
versions = require(CWD + "/versions.json"); versions = require(CWD + '/versions.json');
} }
const readMetadata = require("../../server/readMetadata.js"); const readMetadata = require('../../server/readMetadata.js');
readMetadata.generateMetadataDocs(); readMetadata.generateMetadataDocs();
const Metadata = require("../metadata.js"); const Metadata = require('../metadata.js');
// language dropdown nav item for when translations are enabled // language dropdown nav item for when translations are enabled
class LanguageDropDown extends React.Component { class LanguageDropDown extends React.Component {
render() { render() {
const enabledLanguages = []; const enabledLanguages = [];
let currentLanguage = "English"; let currentLanguage = 'English';
setLanguage(this.props.language); setLanguage(this.props.language);
let helpTranslateString = translate( let helpTranslateString = translate(
"Help Translate|recruit community translators for your project" 'Help Translate|recruit community translators for your project'
); );
// add all enabled languages to dropdown // add all enabled languages to dropdown
translation["languages"].map(lang => { translation['languages'].map(lang => {
if (lang.tag == this.props.language) { if (lang.tag == this.props.language) {
currentLanguage = lang.name; currentLanguage = lang.name;
} }
@ -69,7 +69,7 @@ class LanguageDropDown extends React.Component {
<a id="languages-menu" href="#"> <a id="languages-menu" href="#">
<img <img
className="languages-icon" className="languages-icon"
src={this.props.baseUrl + "img/language.svg"} src={this.props.baseUrl + 'img/language.svg'}
/> />
{currentLanguage} {currentLanguage}
</a> </a>
@ -89,7 +89,7 @@ class LanguageDropDown extends React.Component {
languagesDropDown.className = "hide"; languagesDropDown.className = "hide";
} }
}); });
` `,
}} }}
/> />
</span> </span>
@ -102,7 +102,7 @@ class HeaderNav extends React.Component {
constructor() { constructor() {
super(); super();
this.state = { this.state = {
slideoutActive: false slideoutActive: false,
}; };
} }
// function to generate each header link, used with each object in siteConfig.headerLinks // function to generate each header link, used with each object in siteConfig.headerLinks
@ -127,14 +127,14 @@ class HeaderNav extends React.Component {
} else if (link.doc) { } else if (link.doc) {
// set link to document with current page's language/version // set link to document with current page's language/version
let id; let id;
if (!ENABLE_VERSIONING || this.props.version === "next") { if (!ENABLE_VERSIONING || this.props.version === 'next') {
id = this.props.language + "-" + link.doc; id = this.props.language + '-' + link.doc;
} else { } else {
id = id =
this.props.language + this.props.language +
"-version-" + '-version-' +
(this.props.version || versions[0]) + (this.props.version || versions[0]) +
"-" + '-' +
link.doc; link.doc;
} }
if (!Metadata[id]) { if (!Metadata[id]) {
@ -146,31 +146,31 @@ class HeaderNav extends React.Component {
); );
} }
throw new Error( throw new Error(
"A headerLink is specified with a document that does not exist. No document exists with id: " + 'A headerLink is specified with a document that does not exist. No document exists with id: ' +
link.doc link.doc
); );
} }
href = this.props.config.baseUrl + Metadata[id].permalink; href = this.props.config.baseUrl + Metadata[id].permalink;
} else if (link.page) { } else if (link.page) {
// set link to page with current page's language if appropriate // set link to page with current page's language if appropriate
if (fs.existsSync(CWD + "/pages/en/" + link.page + ".js")) { if (fs.existsSync(CWD + '/pages/en/' + link.page + '.js')) {
href = href =
siteConfig.baseUrl + this.props.language + "/" + link.page + ".html"; siteConfig.baseUrl + this.props.language + '/' + link.page + '.html';
} else { } else {
href = siteConfig.baseUrl + link.page + ".html"; href = siteConfig.baseUrl + link.page + '.html';
} }
} else if (link.href) { } else if (link.href) {
// set link to specified href // set link to specified href
href = link.href; href = link.href;
} else if (link.blog) { } else if (link.blog) {
// set link to blog url // set link to blog url
href = this.props.baseUrl + "blog"; href = this.props.baseUrl + 'blog';
} }
return ( return (
<li key={link.label + "page"}> <li key={link.label + 'page'}>
<a href={href} target={link.external ? "_blank" : "_self"}> <a href={href} target={link.external ? '_blank' : '_self'}>
{translation[this.props.language] {translation[this.props.language]
? translation[this.props.language]["localized-strings"][link.label] ? translation[this.props.language]['localized-strings'][link.label]
: link.label} : link.label}
</a> </a>
</li> </li>
@ -181,8 +181,8 @@ class HeaderNav extends React.Component {
const versionsLink = const versionsLink =
this.props.baseUrl + this.props.baseUrl +
(ENABLE_TRANSLATION (ENABLE_TRANSLATION
? this.props.language + "/versions.html" ? this.props.language + '/versions.html'
: "versions.html"); : 'versions.html');
return ( return (
<div className="fixedHeaderContainer"> <div className="fixedHeaderContainer">
<div className="headerWrapper wrapper"> <div className="headerWrapper wrapper">
@ -218,26 +218,30 @@ class HeaderNav extends React.Component {
} }
}); });
if (!languages) { if (!languages) {
headerLinks.push({ languages: true }); headerLinks.push({languages: true});
} }
let search = false; let search = false;
headerLinks.forEach(link => { headerLinks.forEach(link => {
if (link.doc && !fs.existsSync(CWD + "/../" + readMetadata.getDocsPath() + "/")) { if (
link.doc &&
!fs.existsSync(CWD + '/../' + readMetadata.getDocsPath() + '/')
) {
throw new Error( throw new Error(
"You have 'doc' in your headerLinks, but no '" + readMetadata.getDocsPath() + "You have 'doc' in your headerLinks, but no '" +
readMetadata.getDocsPath() +
"' folder exists one level up from " + "' folder exists one level up from " +
"'website' folder. Did you run `docusaurus-init` or `npm run examples`? If so, " + "'website' folder. Did you run `docusaurus-init` or `npm run examples`? If so, " +
"make sure you rename 'docs-examples-from-docusaurus' to 'docs'." "make sure you rename 'docs-examples-from-docusaurus' to 'docs'."
); );
} }
if (link.blog && !fs.existsSync(CWD + "/blog/")) { if (link.blog && !fs.existsSync(CWD + '/blog/')) {
throw new Error( throw new Error(
"You have 'blog' in your headerLinks, but no 'blog' folder exists in your " + "You have 'blog' in your headerLinks, but no 'blog' folder exists in your " +
"'website' folder. Did you run `docusaurus-init` or `npm run examples`? If so, " + "'website' folder. Did you run `docusaurus-init` or `npm run examples`? If so, " +
"make sure you rename 'blog-examples-from-docusaurus' to 'blog'." "make sure you rename 'blog-examples-from-docusaurus' to 'blog'."
); );
} }
if (link.page && !fs.existsSync(CWD + "/pages/")) { if (link.page && !fs.existsSync(CWD + '/pages/')) {
throw new Error( throw new Error(
"You have 'page' in your headerLinks, but no 'pages' folder exists in your " + "You have 'page' in your headerLinks, but no 'pages' folder exists in your " +
"'website' folder." "'website' folder."
@ -249,7 +253,7 @@ class HeaderNav extends React.Component {
} }
}); });
if (!search && this.props.config.algolia) { if (!search && this.props.config.algolia) {
headerLinks.push({ search: true }); headerLinks.push({search: true});
} }
return ( return (
<div className="navigationWrapper navigationSlider"> <div className="navigationWrapper navigationSlider">

View file

@ -5,11 +5,11 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); const React = require('react');
const classNames = require("classnames"); const classNames = require('classnames');
const siteConfig = require(process.cwd() + "/siteConfig.js"); const siteConfig = require(process.cwd() + '/siteConfig.js');
const translation = require("../../server/translation.js"); const translation = require('../../server/translation.js');
class SideNav extends React.Component { class SideNav extends React.Component {
render() { render() {
@ -39,7 +39,7 @@ class SideNav extends React.Component {
toggler.onclick = function() { toggler.onclick = function() {
nav.classList.toggle('docsSliderActive'); nav.classList.toggle('docsSliderActive');
}; };
` `,
}} }}
/> />
</nav> </nav>
@ -56,7 +56,7 @@ class SideNav extends React.Component {
// return appropriately translated category string // return appropriately translated category string
getLocalizedCategoryString(category) { getLocalizedCategoryString(category) {
let categoryString = translation[this.props.language] let categoryString = translation[this.props.language]
? translation[this.props.language]["localized-strings"][category] || ? translation[this.props.language]['localized-strings'][category] ||
category category
: category; : category;
return categoryString; return categoryString;
@ -69,12 +69,12 @@ class SideNav extends React.Component {
if (sbTitle) { if (sbTitle) {
localizedString = i18n localizedString = i18n
? i18n["localized-strings"][sbTitle] || sbTitle ? i18n['localized-strings'][sbTitle] || sbTitle
: sbTitle; : sbTitle;
} else { } else {
const id = metadata.original_id || metadata.localized_id; const id = metadata.original_id || metadata.localized_id;
localizedString = i18n localizedString = i18n
? i18n["localized-strings"][id] || metadata.title ? i18n['localized-strings'][id] || metadata.title
: metadata.title; : metadata.title;
} }
return localizedString; return localizedString;
@ -88,16 +88,16 @@ class SideNav extends React.Component {
return siteConfig.baseUrl + metadata.permalink; return siteConfig.baseUrl + metadata.permalink;
} }
if (metadata.path) { if (metadata.path) {
return siteConfig.baseUrl + "blog/" + metadata.path; return siteConfig.baseUrl + 'blog/' + metadata.path;
} }
return null; return null;
} }
renderItemLink(link) { renderItemLink(link) {
const itemClasses = classNames("navListItem", { const itemClasses = classNames('navListItem', {
navListItemActive: link.id === this.props.current.id navListItemActive: link.id === this.props.current.id,
}); });
const linkClasses = classNames("navItem", { const linkClasses = classNames('navItem', {
navItemActive: link.id === this.props.current.id navItemActive: link.id === this.props.current.id,
}); });
return ( return (
<li className={itemClasses} key={link.id}> <li className={itemClasses} key={link.id}>
@ -109,6 +109,6 @@ class SideNav extends React.Component {
} }
} }
SideNav.defaultProps = { SideNav.defaultProps = {
contents: [] contents: [],
}; };
module.exports = SideNav; module.exports = SideNav;

View file

@ -8,33 +8,33 @@
module.exports = string => { module.exports = string => {
// var accents = "àáäâèéëêìíïîòóöôùúüûñç"; // var accents = "àáäâèéëêìíïîòóöôùúüûñç";
const accents = const accents =
"\u00e0\u00e1\u00e4\u00e2\u00e8" + '\u00e0\u00e1\u00e4\u00e2\u00e8' +
"\u00e9\u00eb\u00ea\u00ec\u00ed\u00ef" + '\u00e9\u00eb\u00ea\u00ec\u00ed\u00ef' +
"\u00ee\u00f2\u00f3\u00f6\u00f4\u00f9" + '\u00ee\u00f2\u00f3\u00f6\u00f4\u00f9' +
"\u00fa\u00fc\u00fb\u00f1\u00e7"; '\u00fa\u00fc\u00fb\u00f1\u00e7';
const without = "aaaaeeeeiiiioooouuuunc"; const without = 'aaaaeeeeiiiioooouuuunc';
let slug = string let slug = string
.toString() .toString()
// Handle uppercase characters // Handle uppercase characters
.toLowerCase() .toLowerCase()
// Handle accentuated characters // Handle accentuated characters
.replace(new RegExp("[" + accents + "]", "g"), c => { .replace(new RegExp('[' + accents + ']', 'g'), c => {
return without.charAt(accents.indexOf(c)); return without.charAt(accents.indexOf(c));
}) })
// Replace `.`, `(` and `?` with blank string like Github does // Replace `.`, `(` and `?` with blank string like Github does
.replace(/\.|\(|\?/g, "") .replace(/\.|\(|\?/g, '')
// Dash special characters // Dash special characters
.replace(/[^a-z0-9]/g, "-") .replace(/[^a-z0-9]/g, '-')
// Compress multiple dash // Compress multiple dash
.replace(/-+/g, "-") .replace(/-+/g, '-')
// Trim dashes // Trim dashes
.replace(/^-|-$/g, ""); .replace(/^-|-$/g, '');
// Add trailing `-` if string contains ` ...` in the end like Github does // Add trailing `-` if string contains ` ...` in the end like Github does
if (/\s[.]{1,}/.test(string)) { if (/\s[.]{1,}/.test(string)) {
slug += "-"; slug += '-';
} }
return slug; return slug;

View file

@ -7,8 +7,8 @@
// Remove the indentation introduced by JSX // Remove the indentation introduced by JSX
function unindent(code) { function unindent(code) {
const lines = code.split("\n"); const lines = code.split('\n');
if (lines[0] === "") { if (lines[0] === '') {
lines.shift(); lines.shift();
} }
if (lines.length <= 1) { if (lines.length <= 1) {
@ -17,9 +17,9 @@ function unindent(code) {
const indent = lines[0].match(/^\s*/)[0]; const indent = lines[0].match(/^\s*/)[0];
for (let i = 0; i < lines.length; ++i) { for (let i = 0; i < lines.length; ++i) {
lines[i] = lines[i].replace(new RegExp("^" + indent), ""); lines[i] = lines[i].replace(new RegExp('^' + indent), '');
} }
return lines.join("\n"); return lines.join('\n');
} }
module.exports = unindent; module.exports = unindent;

View file

@ -7,25 +7,25 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
require("babel-register")({ require('babel-register')({
babelrc: false, babelrc: false,
only: [__dirname, process.cwd() + "/core"], only: [__dirname, process.cwd() + '/core'],
plugins: [require("./server/translate-plugin.js")], plugins: [require('./server/translate-plugin.js')],
presets: ["react", "latest"] presets: ['react', 'latest'],
}); });
// initial check that required files are present // initial check that required files are present
const chalk = require("chalk"); const chalk = require('chalk');
const fs = require("fs"); const fs = require('fs');
const CWD = process.cwd(); const CWD = process.cwd();
if (!fs.existsSync(CWD + "/siteConfig.js")) { if (!fs.existsSync(CWD + '/siteConfig.js')) {
console.error( console.error(
chalk.red("Error: No siteConfig.js file found in website folder!") chalk.red('Error: No siteConfig.js file found in website folder!')
); );
process.exit(1); process.exit(1);
} }
// generate rss feed // generate rss feed
const feed = require("./server/feed.js"); const feed = require('./server/feed.js');
console.log(feed()); console.log(feed());

View file

@ -7,17 +7,17 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const shell = require("shelljs"); const shell = require('shelljs');
if (!shell.which("git")) { if (!shell.which('git')) {
shell.echo("Sorry, this script requires git"); shell.echo('Sorry, this script requires git');
shell.exit(1); shell.exit(1);
} }
const siteConfig = require(process.cwd() + "/siteConfig.js"); const siteConfig = require(process.cwd() + '/siteConfig.js');
const GIT_USER = process.env.GIT_USER; const GIT_USER = process.env.GIT_USER;
const CURRENT_BRANCH = const CURRENT_BRANCH =
process.env.CIRCLE_BRANCH || shell.exec("git rev-parse --abbrev-ref HEAD"); process.env.CIRCLE_BRANCH || shell.exec('git rev-parse --abbrev-ref HEAD');
const ORGANIZATION_NAME = const ORGANIZATION_NAME =
siteConfig.organizationName || siteConfig.organizationName ||
process.env.ORGANIZATION_NAME || process.env.ORGANIZATION_NAME ||
@ -30,7 +30,8 @@ const IS_PULL_REQUEST =
process.env.CI_PULL_REQUEST || process.env.CIRCLE_PULL_REQUEST; process.env.CI_PULL_REQUEST || process.env.CIRCLE_PULL_REQUEST;
const USE_SSH = process.env.USE_SSH; const USE_SSH = process.env.USE_SSH;
// github.io indicates organization repos that deploy via master. All others use gh-pages. // github.io indicates organization repos that deploy via master. All others use gh-pages.
const DEPLOYMENT_BRANCH = PROJECT_NAME.indexOf(".github.io") !== -1 ? "master" : "gh-pages"; const DEPLOYMENT_BRANCH =
PROJECT_NAME.indexOf('.github.io') !== -1 ? 'master' : 'gh-pages';
if (!ORGANIZATION_NAME) { if (!ORGANIZATION_NAME) {
shell.echo( shell.echo(
@ -47,14 +48,16 @@ if (!PROJECT_NAME) {
} }
let remoteBranch; let remoteBranch;
if (USE_SSH === "true") { if (USE_SSH === 'true') {
remoteBranch = `git@github.com:${ORGANIZATION_NAME}/${PROJECT_NAME}.git`; remoteBranch = `git@github.com:${ORGANIZATION_NAME}/${PROJECT_NAME}.git`;
} else { } else {
remoteBranch = `https://${GIT_USER}@github.com/${ORGANIZATION_NAME}/${PROJECT_NAME}.git`; remoteBranch = `https://${GIT_USER}@github.com/${ORGANIZATION_NAME}/${
PROJECT_NAME
}.git`;
} }
if (IS_PULL_REQUEST) { if (IS_PULL_REQUEST) {
shell.echo("Skipping deploy on a pull request"); shell.echo('Skipping deploy on a pull request');
shell.exit(0); shell.exit(0);
} }
@ -66,18 +69,18 @@ if (CURRENT_BRANCH === DEPLOYMENT_BRANCH) {
} }
if (shell.exec(`node ${__dirname}/build-files.js`).code) { if (shell.exec(`node ${__dirname}/build-files.js`).code) {
shell.echo("Error: generating html failed"); shell.echo('Error: generating html failed');
shell.exit(1); shell.exit(1);
} }
shell.cd(process.cwd()); shell.cd(process.cwd());
shell.cd("build"); shell.cd('build');
if ( if (
shell.exec(`git clone ${remoteBranch} ${PROJECT_NAME}-${DEPLOYMENT_BRANCH}`) shell.exec(`git clone ${remoteBranch} ${PROJECT_NAME}-${DEPLOYMENT_BRANCH}`)
.code !== 0 .code !== 0
) { ) {
shell.echo("Error: git clone failed"); shell.echo('Error: git clone failed');
shell.exit(1); shell.exit(1);
} }
@ -91,7 +94,8 @@ if (shell.exec(`git checkout origin/${DEPLOYMENT_BRANCH}`).code !== 0) {
} else { } else {
if ( if (
shell.exec(`git checkout -b ${DEPLOYMENT_BRANCH}`).code + shell.exec(`git checkout -b ${DEPLOYMENT_BRANCH}`).code +
shell.exec(`git branch --set-upstream-to=origin/${DEPLOYMENT_BRANCH}`).code !== shell.exec(`git branch --set-upstream-to=origin/${DEPLOYMENT_BRANCH}`)
.code !==
0 0
) { ) {
shell.echo(`Error: Git checkout ${DEPLOYMENT_BRANCH} failed`); shell.echo(`Error: Git checkout ${DEPLOYMENT_BRANCH} failed`);
@ -99,30 +103,34 @@ if (shell.exec(`git checkout origin/${DEPLOYMENT_BRANCH}`).code !== 0) {
} }
} }
shell.exec("git rm -rf ."); shell.exec('git rm -rf .');
shell.cd("../.."); shell.cd('../..');
shell.cp( shell.cp(
"-R", '-R',
`build/${PROJECT_NAME}/*`, `build/${PROJECT_NAME}/*`,
`build/${PROJECT_NAME}-${DEPLOYMENT_BRANCH}/` `build/${PROJECT_NAME}-${DEPLOYMENT_BRANCH}/`
); );
shell.cd(`build/${PROJECT_NAME}-${DEPLOYMENT_BRANCH}`); shell.cd(`build/${PROJECT_NAME}-${DEPLOYMENT_BRANCH}`);
const currentCommit = shell.exec("git rev-parse HEAD").stdout.trim(); const currentCommit = shell.exec('git rev-parse HEAD').stdout.trim();
shell.exec("git add --all"); shell.exec('git add --all');
shell.exec( shell.exec(
`git commit -m "Deploy website" -m "Deploy website version based on ${currentCommit}"` `git commit -m "Deploy website" -m "Deploy website version based on ${
currentCommit
}"`
); );
if (shell.exec(`git push origin ${DEPLOYMENT_BRANCH}`).code !== 0) { if (shell.exec(`git push origin ${DEPLOYMENT_BRANCH}`).code !== 0) {
shell.echo("Error: Git push failed"); shell.echo('Error: Git push failed');
shell.exit(1); shell.exit(1);
} else { } else {
shell.echo( shell.echo(
`Website is live at: https://${ORGANIZATION_NAME}.github.io/${PROJECT_NAME}/` `Website is live at: https://${ORGANIZATION_NAME}.github.io/${
PROJECT_NAME
}/`
); );
shell.exit(0); shell.exit(0);
} }

View file

@ -7,35 +7,35 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const chalk = require("chalk"); const chalk = require('chalk');
const fs = require("fs"); const fs = require('fs');
const glob = require("glob"); const glob = require('glob');
const path = require("path"); const path = require('path');
const readMetadata = require("./server/readMetadata.js"); const readMetadata = require('./server/readMetadata.js');
const CWD = process.cwd(); const CWD = process.cwd();
// escape appropriate characters in a string to be used in a regex // escape appropriate characters in a string to be used in a regex
RegExp.escape = function(s) { RegExp.escape = function(s) {
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&"); return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}; };
// generate a doc header from metadata // generate a doc header from metadata
function makeHeader(metadata) { function makeHeader(metadata) {
let header = "---\n"; let header = '---\n';
Object.keys(metadata).forEach(key => { Object.keys(metadata).forEach(key => {
header += key + ": " + metadata[key] + "\n"; header += key + ': ' + metadata[key] + '\n';
}); });
header += "---\n"; header += '---\n';
return header; return header;
} }
let currentVersion, newVersion; let currentVersion, newVersion;
const program = require("commander"); const program = require('commander');
program program
.arguments("<version_name> <new_version_name>") .arguments('<version_name> <new_version_name>')
.action((ver1, ver2) => { .action((ver1, ver2) => {
currentVersion = ver1; currentVersion = ver1;
newVersion = ver2; newVersion = ver2;
@ -45,58 +45,60 @@ program
// require user to input two command line arguments, current version to be // require user to input two command line arguments, current version to be
// renamed, and new version name // renamed, and new version name
if ( if (
typeof currentVersion === "undefined" || typeof currentVersion === 'undefined' ||
typeof newVersion === "undefined" typeof newVersion === 'undefined'
) { ) {
console.error( console.error(
`${chalk.yellow( `${chalk.yellow(
"Version numbers are not properly specified!" 'Version numbers are not properly specified!'
)}\nSpecify as command line arguments: the current version you wish to rename, then the version number you want to rename it to. ` )}\nSpecify as command line arguments: the current version you wish to rename, then the version number you want to rename it to. `
); );
process.exit(1); process.exit(1);
} }
// error if no versions currently exist // error if no versions currently exist
if (!fs.existsSync(CWD + "/versions.json")) { if (!fs.existsSync(CWD + '/versions.json')) {
console.error( console.error(
`${chalk.yellow( `${chalk.yellow(
"No versions found!" 'No versions found!'
)}\nNo versions.json file currently exists. Use the \`versions\` script if you wish to create new versions.` )}\nNo versions.json file currently exists. Use the \`versions\` script if you wish to create new versions.`
); );
process.exit(1); process.exit(1);
} }
const versions = JSON.parse(fs.readFileSync(CWD + "/versions.json", "utf8")); const versions = JSON.parse(fs.readFileSync(CWD + '/versions.json', 'utf8'));
const versionIndex = versions.indexOf(currentVersion); const versionIndex = versions.indexOf(currentVersion);
// error if current specified version does not exist // error if current specified version does not exist
if (versionIndex < 0) { if (versionIndex < 0) {
console.error( console.error(
`${chalk.yellow( `${chalk.yellow(
"Version " + currentVersion + " does not currently exist!" 'Version ' + currentVersion + ' does not currently exist!'
)}\n Version ${currentVersion} is not in the versions.json file. You can only rename existing versions.` )}\n Version ${
currentVersion
} is not in the versions.json file. You can only rename existing versions.`
); );
process.exit(1); process.exit(1);
} }
// replace old version with new version in versions.json file // replace old version with new version in versions.json file
versions[versionIndex] = newVersion; versions[versionIndex] = newVersion;
fs.writeFileSync(CWD + "/versions.json", JSON.stringify(versions)); fs.writeFileSync(CWD + '/versions.json', JSON.stringify(versions));
// if folder of docs for this version exists, rename folder and rewrite doc // if folder of docs for this version exists, rename folder and rewrite doc
// headers to use new version // headers to use new version
if (fs.existsSync(CWD + "/versioned_docs/version-" + currentVersion)) { if (fs.existsSync(CWD + '/versioned_docs/version-' + currentVersion)) {
fs.renameSync( fs.renameSync(
CWD + "/versioned_docs/version-" + currentVersion, CWD + '/versioned_docs/version-' + currentVersion,
CWD + "/versioned_docs/version-" + newVersion CWD + '/versioned_docs/version-' + newVersion
); );
const files = glob.sync(CWD + "/versioned_docs/version-" + newVersion + "/*"); const files = glob.sync(CWD + '/versioned_docs/version-' + newVersion + '/*');
files.forEach(file => { files.forEach(file => {
const extension = path.extname(file); const extension = path.extname(file);
if (extension !== ".md" && extension !== ".markdown") { if (extension !== '.md' && extension !== '.markdown') {
return; return;
} }
const res = readMetadata.extractMetadata(fs.readFileSync(file, "utf8")); const res = readMetadata.extractMetadata(fs.readFileSync(file, 'utf8'));
const metadata = res.metadata; const metadata = res.metadata;
const rawContent = res.rawContent; const rawContent = res.rawContent;
if (!metadata.id) { if (!metadata.id) {
@ -113,21 +115,21 @@ if (fs.existsSync(CWD + "/versioned_docs/version-" + currentVersion)) {
// if sidebar file exists for this version, rename sidebar file and rewrite // if sidebar file exists for this version, rename sidebar file and rewrite
// doc ids in the file // doc ids in the file
let currentSidebarFile = let currentSidebarFile =
CWD + "/versioned_sidebars/version-" + currentVersion + "-sidebar.json"; CWD + '/versioned_sidebars/version-' + currentVersion + '-sidebar.json';
let newSidebarFile = let newSidebarFile =
CWD + "/versioned_sidebars/version-" + newVersion + "-sidebar.json"; CWD + '/versioned_sidebars/version-' + newVersion + '-sidebar.json';
if (fs.existsSync(currentSidebarFile)) { if (fs.existsSync(currentSidebarFile)) {
fs.renameSync(currentSidebarFile, newSidebarFile); fs.renameSync(currentSidebarFile, newSidebarFile);
let sidebarContent = fs.readFileSync(newSidebarFile, "utf8"); let sidebarContent = fs.readFileSync(newSidebarFile, 'utf8');
sidebarContent = sidebarContent.replace( sidebarContent = sidebarContent.replace(
new RegExp(`version-${RegExp.escape(currentVersion)}-`, "g"), new RegExp(`version-${RegExp.escape(currentVersion)}-`, 'g'),
`version-${newVersion}-` `version-${newVersion}-`
); );
fs.writeFileSync(newSidebarFile, sidebarContent); fs.writeFileSync(newSidebarFile, sidebarContent);
} }
console.log( console.log(
`${chalk.green("Successfully enamed version ")}${chalk.yellow( `${chalk.green('Successfully enamed version ')}${chalk.yellow(
currentVersion currentVersion
)}${chalk.green(" to version ")}${chalk.yellow(newVersion)}\n` )}${chalk.green(' to version ')}${chalk.yellow(newVersion)}\n`
); );

View file

@ -5,18 +5,18 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const fs = require("fs-extra"); const fs = require('fs-extra');
const path = require("path"); const path = require('path');
const os = require("os"); const os = require('os');
const Feed = require("feed"); const Feed = require('feed');
const chalk = require("chalk"); const chalk = require('chalk');
const CWD = process.cwd(); const CWD = process.cwd();
const siteConfig = require(CWD + "/siteConfig.js"); const siteConfig = require(CWD + '/siteConfig.js');
const blogFolder = path.resolve("../blog/"); const blogFolder = path.resolve('../blog/');
const blogRootURL = siteConfig.url + "/blog"; const blogRootURL = siteConfig.url + '/blog';
const jestImage = siteConfig.url + siteConfig.headerIcon; const jestImage = siteConfig.url + siteConfig.headerIcon;
/****************************************************************************/ /****************************************************************************/
@ -24,40 +24,40 @@ const jestImage = siteConfig.url + siteConfig.headerIcon;
let readMetadata; let readMetadata;
let Metadata; let Metadata;
readMetadata = require("./readMetadata.js"); readMetadata = require('./readMetadata.js');
readMetadata.generateMetadataDocs(); readMetadata.generateMetadataDocs();
Metadata = require("../core/metadata.js"); Metadata = require('../core/metadata.js');
/****************************************************************************/ /****************************************************************************/
module.exports = function(type) { module.exports = function(type) {
console.log("feed.js triggered..."); console.log('feed.js triggered...');
type = type || "rss"; type = type || 'rss';
readMetadata.generateMetadataBlog(); readMetadata.generateMetadataBlog();
const MetadataBlog = require("../core/MetadataBlog.js"); const MetadataBlog = require('../core/MetadataBlog.js');
const feed = new Feed({ const feed = new Feed({
title: siteConfig.title + " Blog", title: siteConfig.title + ' Blog',
description: description:
"The best place to stay up-to-date with the latest " + 'The best place to stay up-to-date with the latest ' +
siteConfig.title + siteConfig.title +
" news and events.", ' news and events.',
id: blogRootURL, id: blogRootURL,
link: blogRootURL, link: blogRootURL,
image: jestImage, image: jestImage,
copyright: siteConfig.copyright, copyright: siteConfig.copyright,
updated: new Date(MetadataBlog[0].date) updated: new Date(MetadataBlog[0].date),
}); });
MetadataBlog.forEach(post => { MetadataBlog.forEach(post => {
const url = blogRootURL + "/" + post.path; const url = blogRootURL + '/' + post.path;
let content = ""; let content = '';
if (post.content.indexOf("<!--truncate-->") == -1) { if (post.content.indexOf('<!--truncate-->') == -1) {
content = post.content.trim().substring(0, 250); content = post.content.trim().substring(0, 250);
} else { } else {
let contentArr = post.content.split("<!--truncate-->"); let contentArr = post.content.split('<!--truncate-->');
if (contentArr.length > 0) { if (contentArr.length > 0) {
content = contentArr[0]; content = contentArr[0];
} }
@ -69,13 +69,13 @@ module.exports = function(type) {
author: [ author: [
{ {
name: post.author, name: post.author,
link: post.authorURL link: post.authorURL,
} },
], ],
date: new Date(post.date), date: new Date(post.date),
description: content description: content,
}); });
}); });
return type === "rss" ? feed.rss2() : feed.atom1(); return type === 'rss' ? feed.rss2() : feed.atom1();
}; };

View file

@ -6,51 +6,51 @@
*/ */
function execute() { function execute() {
const extractTranslations = require("../write-translations.js"); const extractTranslations = require('../write-translations.js');
const CWD = process.cwd(); const CWD = process.cwd();
const fs = require("fs-extra"); const fs = require('fs-extra');
const readMetadata = require("./readMetadata.js"); const readMetadata = require('./readMetadata.js');
const renderToStaticMarkup = require("react-dom/server").renderToStaticMarkup; const renderToStaticMarkup = require('react-dom/server').renderToStaticMarkup;
const path = require("path"); const path = require('path');
const toSlug = require("../core/toSlug.js"); const toSlug = require('../core/toSlug.js');
const React = require("react"); const React = require('react');
const mkdirp = require("mkdirp"); const mkdirp = require('mkdirp');
const glob = require("glob"); const glob = require('glob');
const chalk = require("chalk"); const chalk = require('chalk');
const Site = require("../core/Site.js"); const Site = require('../core/Site.js');
const siteConfig = require(CWD + "/siteConfig.js"); const siteConfig = require(CWD + '/siteConfig.js');
const translate = require("./translate.js"); const translate = require('./translate.js');
const versionFallback = require("./versionFallback.js"); const versionFallback = require('./versionFallback.js');
const feed = require("./feed.js"); const feed = require('./feed.js');
const sitemap = require("./sitemap.js"); const sitemap = require('./sitemap.js');
const join = path.join; const join = path.join;
const ENABLE_TRANSLATION = fs.existsSync(join(CWD, "languages.js")); const ENABLE_TRANSLATION = fs.existsSync(join(CWD, 'languages.js'));
const ENABLE_VERSIONING = fs.existsSync(join(CWD, "versions.json")); const ENABLE_VERSIONING = fs.existsSync(join(CWD, 'versions.json'));
let languages; let languages;
if (ENABLE_TRANSLATION) { if (ENABLE_TRANSLATION) {
languages = require(CWD + "/languages.js"); languages = require(CWD + '/languages.js');
} else { } else {
languages = [ languages = [
{ {
enabled: true, enabled: true,
name: "English", name: 'English',
tag: "en" tag: 'en',
} },
]; ];
} }
// create the folder path for a file if it does not exist, then write the file // create the folder path for a file if it does not exist, then write the file
function writeFileAndCreateFolder(file, content) { function writeFileAndCreateFolder(file, content) {
mkdirp.sync(file.replace(new RegExp("/[^/]*$"), "")); mkdirp.sync(file.replace(new RegExp('/[^/]*$'), ''));
fs.writeFileSync(file, content); fs.writeFileSync(file, content);
} }
const TABLE_OF_CONTENTS_TOKEN = "<AUTOGENERATED_TABLE_OF_CONTENTS>"; const TABLE_OF_CONTENTS_TOKEN = '<AUTOGENERATED_TABLE_OF_CONTENTS>';
// takes the content of a doc article and returns the content with a table of // takes the content of a doc article and returns the content with a table of
// contents inserted // contents inserted
@ -64,7 +64,7 @@ function execute() {
const tableOfContents = headers const tableOfContents = headers
.map(header => ` - [${header}](#${toSlug(header)})`) .map(header => ` - [${header}](#${toSlug(header)})`)
.join("\n"); .join('\n');
return rawContent.replace(TABLE_OF_CONTENTS_TOKEN, tableOfContents); return rawContent.replace(TABLE_OF_CONTENTS_TOKEN, tableOfContents);
}; };
@ -83,7 +83,7 @@ function execute() {
return false; return false;
} }
console.log("generate.js triggered..."); console.log('generate.js triggered...');
// array of tags of enabled languages // array of tags of enabled languages
const enabledLanguages = []; const enabledLanguages = [];
@ -92,7 +92,7 @@ function execute() {
}); });
readMetadata.generateMetadataDocs(); readMetadata.generateMetadataDocs();
const Metadata = require("../core/metadata.js"); const Metadata = require('../core/metadata.js');
// TODO: what if the project is a github org page? We should not use // TODO: what if the project is a github org page? We should not use
// siteConfig.projectName in this case. Otherwise a GitHub org doc URL would // siteConfig.projectName in this case. Otherwise a GitHub org doc URL would
@ -102,30 +102,30 @@ function execute() {
// `title`. `projectName` is only used to generate a folder, which isn't // `title`. `projectName` is only used to generate a folder, which isn't
// needed when the project's a GitHub org page // needed when the project's a GitHub org page
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 // 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 // change relative markdown links that work on GitHub into actual site links
const mdToHtml = {}; const mdToHtml = {};
Object.keys(Metadata).forEach(id => { Object.keys(Metadata).forEach(id => {
const metadata = Metadata[id]; const metadata = Metadata[id];
if (metadata.language !== "en" || metadata.original_id) { if (metadata.language !== 'en' || metadata.original_id) {
return; return;
} }
let htmlLink = let htmlLink =
siteConfig.baseUrl + metadata.permalink.replace("/next/", "/"); siteConfig.baseUrl + metadata.permalink.replace('/next/', '/');
if (htmlLink.includes("/docs/en/")) { if (htmlLink.includes('/docs/en/')) {
htmlLink = htmlLink.replace("/docs/en/", "/docs/en/VERSION/"); htmlLink = htmlLink.replace('/docs/en/', '/docs/en/VERSION/');
} else { } else {
htmlLink = htmlLink.replace("/docs/", "/docs/VERSION/"); htmlLink = htmlLink.replace('/docs/', '/docs/VERSION/');
} }
mdToHtml[metadata.source] = htmlLink; 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');
fs.removeSync(join(CWD, "build")); fs.removeSync(join(CWD, 'build'));
// create html files for all docs by going through all doc ids // create html files for all docs by going through all doc ids
Object.keys(Metadata).forEach(id => { Object.keys(Metadata).forEach(id => {
@ -133,16 +133,16 @@ function execute() {
// determine what file to use according to its id // determine what file to use according to its id
let file; let file;
if (metadata.original_id) { if (metadata.original_id) {
if (ENABLE_TRANSLATION && metadata.language !== "en") { if (ENABLE_TRANSLATION && metadata.language !== 'en') {
file = join(CWD, "translated_docs", metadata.language, metadata.source); file = join(CWD, 'translated_docs', metadata.language, metadata.source);
} else { } else {
file = join(CWD, "versioned_docs", metadata.source); file = join(CWD, 'versioned_docs', metadata.source);
} }
} else { } else {
if (metadata.language === "en") { if (metadata.language === 'en') {
file = join(CWD, "..", readMetadata.getDocsPath(), metadata.source); file = join(CWD, '..', readMetadata.getDocsPath(), metadata.source);
} else { } else {
file = join(CWD, "translated_docs", metadata.language, metadata.source); file = join(CWD, 'translated_docs', metadata.language, metadata.source);
} }
} }
@ -150,7 +150,7 @@ function execute() {
return; return;
} }
let rawContent = readMetadata.extractMetadata(fs.readFileSync(file, "utf8")) let rawContent = readMetadata.extractMetadata(fs.readFileSync(file, 'utf8'))
.rawContent; .rawContent;
const language = metadata.language; const language = metadata.language;
@ -163,36 +163,36 @@ function execute() {
let latestVersion; let latestVersion;
if (ENABLE_VERSIONING) { if (ENABLE_VERSIONING) {
latestVersion = JSON.parse( latestVersion = JSON.parse(
fs.readFileSync(join(CWD, "versions.json"), "utf8") fs.readFileSync(join(CWD, 'versions.json'), 'utf8')
)[0]; )[0];
} }
// 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(function(key, index) { Object.keys(mdToHtml).forEach(function(key, index) {
let link = mdToHtml[key]; let link = mdToHtml[key];
link = link.replace("/en/", "/" + language + "/"); link = link.replace('/en/', '/' + language + '/');
link = link.replace( link = link.replace(
"/VERSION/", '/VERSION/',
metadata.version && metadata.version !== latestVersion metadata.version && metadata.version !== latestVersion
? "/" + metadata.version + "/" ? '/' + metadata.version + '/'
: "/" : '/'
); );
// replace relative links without "./" // replace relative links without "./"
rawContent = rawContent.replace( rawContent = rawContent.replace(
new RegExp("\\]\\(" + key, "g"), new RegExp('\\]\\(' + key, 'g'),
"](" + link '](' + link
); );
// replace relative links with "./" // replace relative links with "./"
rawContent = rawContent.replace( rawContent = rawContent.replace(
new RegExp("\\]\\(\\./" + key, "g"), new RegExp('\\]\\(\\./' + key, 'g'),
"](" + link '](' + link
); );
}); });
// replace any relative links to static assets to absolute links // replace any relative links to static assets to absolute links
rawContent = rawContent.replace( rawContent = rawContent.replace(
/\]\(assets\//g, /\]\(assets\//g,
"](" + siteConfig.baseUrl + "docs/assets/" '](' + siteConfig.baseUrl + 'docs/assets/'
); );
const docComp = ( const docComp = (
@ -206,7 +206,7 @@ function execute() {
writeFileAndCreateFolder(targetFile, str); writeFileAndCreateFolder(targetFile, str);
// generate english page redirects when languages are enabled // generate english page redirects when languages are enabled
if (ENABLE_TRANSLATION && metadata.permalink.indexOf("docs/en") !== -1) { if (ENABLE_TRANSLATION && metadata.permalink.indexOf('docs/en') !== -1) {
const redirectComp = ( const redirectComp = (
<Redirect <Redirect
metadata={metadata} metadata={metadata}
@ -220,76 +220,75 @@ function execute() {
// create a redirects page for doc files // create a redirects page for doc files
const redirectFile = join( const redirectFile = join(
buildDir, buildDir,
metadata.permalink.replace("docs/en", "docs") metadata.permalink.replace('docs/en', 'docs')
); );
writeFileAndCreateFolder(redirectFile, redirectStr); writeFileAndCreateFolder(redirectFile, redirectStr);
} }
}); });
// copy docs assets if they exist // copy docs assets if they exist
if (fs.existsSync(join(CWD, "..", readMetadata.getDocsPath(), "assets"))) { if (fs.existsSync(join(CWD, '..', readMetadata.getDocsPath(), 'assets'))) {
fs.copySync( fs.copySync(
join(CWD, readMetadata.getDocsPath(), "assets"), join(CWD, readMetadata.getDocsPath(), 'assets'),
join(buildDir, "docs", "assets") join(buildDir, 'docs', 'assets')
); );
} }
// create html files for all blog posts (each article) // create html files for all blog posts (each article)
if (fs.existsSync(join(__dirname, "..", "core", "MetadataBlog.js"))) { if (fs.existsSync(join(__dirname, '..', 'core', 'MetadataBlog.js'))) {
fs.removeSync(join(__dirname, "..", "core", "MetadataBlog.js")); fs.removeSync(join(__dirname, '..', 'core', 'MetadataBlog.js'));
} }
readMetadata.generateMetadataBlog(); readMetadata.generateMetadataBlog();
const MetadataBlog = require("../core/MetadataBlog.js"); const MetadataBlog = require('../core/MetadataBlog.js');
const BlogPostLayout = require("../core/BlogPostLayout.js"); const BlogPostLayout = require('../core/BlogPostLayout.js');
let files = glob.sync(join(CWD, "blog", "**", "*.*")); let files = glob.sync(join(CWD, 'blog', '**', '*.*'));
files files
.sort() .sort()
.reverse() .reverse()
.forEach(file => { .forEach(file => {
const extension = path.extname(file); const extension = path.extname(file);
if (extension !== ".md" && extension !== ".markdown") { if (extension !== '.md' && extension !== '.markdown') {
return; return;
} }
// convert filename to use slashes // convert filename to use slashes
const filePath = path const filePath = path
.basename(file) .basename(file)
.replace("-", "/") .replace('-', '/')
.replace("-", "/") .replace('-', '/')
.replace("-", "/") .replace('-', '/')
.replace(/\.md$/, ".html"); .replace(/\.md$/, '.html');
const result = readMetadata.extractMetadata( const result = readMetadata.extractMetadata(
fs.readFileSync(file, { encoding: "utf8" }) fs.readFileSync(file, {encoding: 'utf8'})
); );
const rawContent = result.rawContent; const rawContent = result.rawContent;
const metadata = Object.assign( const metadata = Object.assign(
{ path: filePath, content: rawContent }, {path: filePath, content: rawContent},
result.metadata result.metadata
); );
metadata.id = metadata.title; metadata.id = metadata.title;
let language = "en"; let language = 'en';
const blogPostComp = ( const blogPostComp = (
<BlogPostLayout <BlogPostLayout
metadata={metadata} metadata={metadata}
language={language} language={language}
config={siteConfig} config={siteConfig}>
>
{rawContent} {rawContent}
</BlogPostLayout> </BlogPostLayout>
); );
const str = renderToStaticMarkup(blogPostComp); const str = renderToStaticMarkup(blogPostComp);
let targetFile = join(buildDir, "blog", filePath); let targetFile = join(buildDir, 'blog', filePath);
writeFileAndCreateFolder(targetFile, str); writeFileAndCreateFolder(targetFile, str);
}); });
// create html files for all blog pages (collections of article previews) // create html files for all blog pages (collections of article previews)
const BlogPageLayout = require("../core/BlogPageLayout.js"); const BlogPageLayout = require('../core/BlogPageLayout.js');
const perPage = 10; const perPage = 10;
for (let page = 0; page < Math.ceil(MetadataBlog.length / perPage); page++) { for (let page = 0; page < Math.ceil(MetadataBlog.length / perPage); page++) {
let language = "en"; let language = 'en';
const metadata = { page: page, perPage: perPage }; const metadata = {page: page, perPage: perPage};
const blogPageComp = ( const blogPageComp = (
<BlogPageLayout <BlogPageLayout
metadata={metadata} metadata={metadata}
@ -301,44 +300,44 @@ function execute() {
let targetFile = join( let targetFile = join(
buildDir, buildDir,
"blog", 'blog',
page > 0 ? "page" + (page + 1) : "", page > 0 ? 'page' + (page + 1) : '',
"index.html" 'index.html'
); );
writeFileAndCreateFolder(targetFile, str); writeFileAndCreateFolder(targetFile, str);
} }
// create rss files for all blog pages, if there are any blog files // create rss files for all blog pages, if there are any blog files
if (MetadataBlog.length > 0) { if (MetadataBlog.length > 0) {
let targetFile = join(buildDir, "blog", "feed.xml"); let targetFile = join(buildDir, 'blog', 'feed.xml');
writeFileAndCreateFolder(targetFile, feed()); writeFileAndCreateFolder(targetFile, feed());
targetFile = join(buildDir, "blog", "atom.xml"); targetFile = join(buildDir, 'blog', 'atom.xml');
writeFileAndCreateFolder(targetFile, feed("atom")); writeFileAndCreateFolder(targetFile, feed('atom'));
} }
// create sitemap // create sitemap
if (MetadataBlog.length > 0 && Object.keys(Metadata).length > 0) { if (MetadataBlog.length > 0 && Object.keys(Metadata).length > 0) {
let targetFile = join(buildDir, "sitemap.xml"); let targetFile = join(buildDir, 'sitemap.xml');
sitemap(xml => { sitemap(xml => {
writeFileAndCreateFolder(targetFile, xml); writeFileAndCreateFolder(targetFile, xml);
}); });
} }
// copy blog assets if they exist // copy blog assets if they exist
if (fs.existsSync(join(CWD, "blog", "assets"))) { if (fs.existsSync(join(CWD, 'blog', 'assets'))) {
fs.copySync(join(CWD, "blog", "assets"), join(buildDir, "blog", "assets")); fs.copySync(join(CWD, 'blog', 'assets'), join(buildDir, 'blog', 'assets'));
} }
// copy all static files from docusaurus // copy all static files from docusaurus
files = glob.sync(join(__dirname, "..", "static", "**")); files = glob.sync(join(__dirname, '..', 'static', '**'));
files.forEach(file => { files.forEach(file => {
let targetFile = join( let targetFile = join(
buildDir, buildDir,
// TODO: use x-platform path functions // TODO: use x-platform path functions
file.split("/static/")[1] || "" file.split('/static/')[1] || ''
); );
// parse css files to replace colors according to siteConfig // parse css files to replace colors according to siteConfig
if (file.match(/\.css$/)) { if (file.match(/\.css$/)) {
let cssContent = fs.readFileSync(file, "utf8"); let cssContent = fs.readFileSync(file, 'utf8');
if ( if (
!siteConfig.colors || !siteConfig.colors ||
@ -347,80 +346,80 @@ function execute() {
) { ) {
console.error( console.error(
`${chalk.yellow( `${chalk.yellow(
"Missing color configuration." 'Missing color configuration.'
)} Make sure siteConfig.colors includes primaryColor and secondaryColor fields.` )} Make sure siteConfig.colors includes primaryColor and secondaryColor fields.`
); );
} }
Object.keys(siteConfig.colors).forEach(key => { Object.keys(siteConfig.colors).forEach(key => {
const color = siteConfig.colors[key]; const color = siteConfig.colors[key];
cssContent = cssContent.replace(new RegExp("\\$" + key, "g"), color); cssContent = cssContent.replace(new RegExp('\\$' + key, 'g'), color);
}); });
mkdirp.sync(targetFile.replace(new RegExp("/[^/]*$"), "")); mkdirp.sync(targetFile.replace(new RegExp('/[^/]*$'), ''));
fs.writeFileSync(targetFile, cssContent); fs.writeFileSync(targetFile, cssContent);
} else if (!fs.lstatSync(file).isDirectory()) { } else if (!fs.lstatSync(file).isDirectory()) {
mkdirp.sync(targetFile.replace(new RegExp("/[^/]*$"), "")); mkdirp.sync(targetFile.replace(new RegExp('/[^/]*$'), ''));
fs.copySync(file, targetFile); fs.copySync(file, targetFile);
} }
}); });
// copy all static files from user // copy all static files from user
files = glob.sync(join(CWD, "static", "**")); files = glob.sync(join(CWD, 'static', '**'));
files.forEach(file => { files.forEach(file => {
// parse css files to replace colors according to siteConfig // parse css files to replace colors according to siteConfig
if (file.match(/\.css$/) && !isSeparateCss(file)) { if (file.match(/\.css$/) && !isSeparateCss(file)) {
const mainCss = join(buildDir, "css", "main.css"); const mainCss = join(buildDir, 'css', 'main.css');
let cssContent = fs.readFileSync(file, "utf8"); let cssContent = fs.readFileSync(file, 'utf8');
cssContent = fs.readFileSync(mainCss, "utf8") + "\n" + cssContent; cssContent = fs.readFileSync(mainCss, 'utf8') + '\n' + cssContent;
Object.keys(siteConfig.colors).forEach(key => { Object.keys(siteConfig.colors).forEach(key => {
const color = siteConfig.colors[key]; const color = siteConfig.colors[key];
cssContent = cssContent.replace(new RegExp("\\$" + key, "g"), color); cssContent = cssContent.replace(new RegExp('\\$' + key, 'g'), color);
}); });
fs.writeFileSync(mainCss, cssContent); fs.writeFileSync(mainCss, cssContent);
} else if (!fs.lstatSync(file).isDirectory()) { } else if (!fs.lstatSync(file).isDirectory()) {
let parts = file.split("/static/"); let parts = file.split('/static/');
let targetFile = join(buildDir, parts[1]); let targetFile = join(buildDir, parts[1]);
mkdirp.sync(targetFile.replace(new RegExp("/[^/]*$"), "")); mkdirp.sync(targetFile.replace(new RegExp('/[^/]*$'), ''));
fs.copySync(file, targetFile); fs.copySync(file, targetFile);
} }
}); });
// compile/copy pages from user // compile/copy pages from user
let pagesArr = []; let pagesArr = [];
files = glob.sync(join(CWD, "pages", "**")); files = glob.sync(join(CWD, 'pages', '**'));
files.forEach(file => { files.forEach(file => {
// render .js files to strings // render .js files to strings
if (file.match(/\.js$/)) { if (file.match(/\.js$/)) {
// make temp file for sake of require paths // make temp file for sake of require paths
const parts = file.split("pages"); const parts = file.split('pages');
let tempFile = join(__dirname, "..", "pages", parts[1]); let tempFile = join(__dirname, '..', 'pages', parts[1]);
tempFile = tempFile.replace( tempFile = tempFile.replace(
path.basename(file), path.basename(file),
"temp" + path.basename(file) 'temp' + path.basename(file)
); );
mkdirp.sync(tempFile.replace(new RegExp("/[^/]*$"), "")); mkdirp.sync(tempFile.replace(new RegExp('/[^/]*$'), ''));
fs.copySync(file, tempFile); fs.copySync(file, tempFile);
const ReactComp = require(tempFile); const ReactComp = require(tempFile);
let targetFile = join(buildDir, parts[1]); let targetFile = join(buildDir, parts[1]);
targetFile = targetFile.replace(/\.js$/, ".html"); targetFile = targetFile.replace(/\.js$/, '.html');
const regexLang = /\/pages\/(.*)\//; const regexLang = /\/pages\/(.*)\//;
const match = regexLang.exec(file); const match = regexLang.exec(file);
const langParts = match[1].split("/"); const langParts = match[1].split('/');
if (langParts.indexOf("en") !== -1) { if (langParts.indexOf('en') !== -1) {
// copy and compile a page for each enabled language from the English file // copy and compile a page for each enabled language from the English file
for (let i = 0; i < enabledLanguages.length; i++) { for (let i = 0; i < enabledLanguages.length; i++) {
let language = enabledLanguages[i]; let language = enabledLanguages[i];
// skip conversion from english file if a file exists for this language // skip conversion from english file if a file exists for this language
if ( if (
language !== "en" && language !== 'en' &&
// TODO: use path functions // TODO: use path functions
fs.existsSync(file.replace("/en/", "/" + language + "/")) fs.existsSync(file.replace('/en/', '/' + language + '/'))
) { ) {
continue; continue;
} }
@ -432,13 +431,13 @@ function execute() {
); );
writeFileAndCreateFolder( writeFileAndCreateFolder(
// TODO: use path functions // TODO: use path functions
targetFile.replace("/en/", "/" + language + "/"), targetFile.replace('/en/', '/' + language + '/'),
str str
); );
} }
} else { } else {
// allow for rendering of other files not in pages/en folder // allow for rendering of other files not in pages/en folder
let language = "en"; let language = 'en';
for (let i = 0; i < langParts.length; i++) { for (let i = 0; i < langParts.length; i++) {
if (enabledLanguages.indexOf(langParts[i]) !== -1) { if (enabledLanguages.indexOf(langParts[i]) !== -1) {
language = langParts[i]; language = langParts[i];
@ -455,17 +454,17 @@ function execute() {
fs.removeSync(tempFile); fs.removeSync(tempFile);
} else if (!fs.lstatSync(file).isDirectory()) { } else if (!fs.lstatSync(file).isDirectory()) {
// copy other non .js files // copy other non .js files
let parts = file.split("pages"); let parts = file.split('pages');
let targetFile = join(buildDir, parts[1]); let targetFile = join(buildDir, parts[1]);
mkdirp.sync(targetFile.replace(new RegExp("/[^/]*$"), "")); mkdirp.sync(targetFile.replace(new RegExp('/[^/]*$'), ''));
fs.copySync(file, targetFile); fs.copySync(file, targetFile);
} }
}); });
// copy html files in 'en' to base level as well // copy html files in 'en' to base level as well
files = glob.sync(join(buildDir, "en", "**")); files = glob.sync(join(buildDir, 'en', '**'));
files.forEach(file => { files.forEach(file => {
let targetFile = file.replace(join(buildDir, "en"), join(buildDir)); let targetFile = file.replace(join(buildDir, 'en'), join(buildDir));
if (file.match(/\.html$/)) { if (file.match(/\.html$/)) {
fs.copySync(file, targetFile); fs.copySync(file, targetFile);
} }
@ -473,7 +472,7 @@ function execute() {
// Generate CNAME file if a custom domain is specified in siteConfig // Generate CNAME file if a custom domain is specified in siteConfig
if (siteConfig.cname) { if (siteConfig.cname) {
let targetFile = join(buildDir, "CNAME"); let targetFile = join(buildDir, 'CNAME');
fs.writeFileSync(targetFile, siteConfig.cname); fs.writeFileSync(targetFile, siteConfig.cname);
} }
} }

View file

@ -7,18 +7,18 @@
const CWD = process.cwd(); const CWD = process.cwd();
const Metadata = require("../core/metadata.js"); const Metadata = require('../core/metadata.js');
const fs = require("fs"); const fs = require('fs');
let languages; let languages;
if (fs.existsSync(CWD + "/languages.js")) { if (fs.existsSync(CWD + '/languages.js')) {
languages = require(CWD + "/languages.js"); languages = require(CWD + '/languages.js');
} else { } else {
languages = [ languages = [
{ {
enabled: true, enabled: true,
name: "English", name: 'English',
tag: "en" tag: 'en',
} },
]; ];
} }
@ -57,8 +57,14 @@ function readCategories(sidebar) {
if (!articles[metadata.next]) { if (!articles[metadata.next]) {
throw new Error( throw new Error(
metadata.version metadata.version
? `Improper sidebars file for version ${metadata.version}, document with id '${metadata.next}' not found. Make sure that all documents with ids specified in this version's sidebar file exist and that no ids are repeated.` ? `Improper sidebars file for version ${
: `Improper sidebars.json file, document with id '${metadata.next}' not found. Make sure that documents with the ids specified in sidebars.json exist and that no ids are repeated.` metadata.version
}, document with id '${
metadata.next
}' not found. Make sure that all documents with ids specified in this version's sidebar file exist and that no ids are repeated.`
: `Improper sidebars.json file, document with id '${
metadata.next
}' not found. Make sure that documents with the ids specified in sidebars.json exist and that no ids are repeated.`
); );
} }
previous[articles[metadata.next].id] = metadata.id; previous[articles[metadata.next].id] = metadata.id;
@ -85,7 +91,7 @@ function readCategories(sidebar) {
currentCategory && categories.push(currentCategory); currentCategory && categories.push(currentCategory);
currentCategory = { currentCategory = {
name: metadata.category, name: metadata.category,
links: [] links: [],
}; };
} }
currentCategory.links.push(metadata); currentCategory.links.push(metadata);

View file

@ -7,28 +7,26 @@
const CWD = process.cwd(); const CWD = process.cwd();
const path = require("path"); const path = require('path');
const fs = require("fs"); const fs = require('fs');
const glob = require("glob"); const glob = require('glob');
const chalk = require("chalk"); const chalk = require('chalk');
const siteConfig = require(CWD + "/siteConfig.js"); const siteConfig = require(CWD + '/siteConfig.js');
const versionFallback = require("./versionFallback.js"); const versionFallback = require('./versionFallback.js');
const escapeStringRegexp = require("escape-string-regexp"); const escapeStringRegexp = require('escape-string-regexp');
const ENABLE_VERSIONING = fs.existsSync(CWD + "/versions.json");
const ENABLE_VERSIONING = fs.existsSync(CWD + '/versions.json');
let languages; let languages;
if (fs.existsSync(CWD + "/languages.js")) { if (fs.existsSync(CWD + '/languages.js')) {
languages = require(CWD + "/languages.js"); languages = require(CWD + '/languages.js');
} else { } else {
languages = [ languages = [
{ {
enabled: true, enabled: true,
name: "English", name: 'English',
tag: "en" tag: 'en',
} },
]; ];
} }
@ -39,15 +37,13 @@ if (fs.existsSync(CWD + "/languages.js")) {
// All .md docs still (currently) must be in one flat directory hierarchy. // All .md docs still (currently) must be in one flat directory hierarchy.
// e.g., docs/whereDocsReallyExist/*.md (all .md files in this dir) // e.g., docs/whereDocsReallyExist/*.md (all .md files in this dir)
function getDocsPath() { function getDocsPath() {
return siteConfig.customDocsPath return siteConfig.customDocsPath ? siteConfig.customDocsPath : 'docs';
? siteConfig.customDocsPath
: "docs";
} }
// returns map from id to object containing sidebar ordering info // returns map from id to object containing sidebar ordering info
function readSidebar() { function readSidebar() {
let allSidebars; let allSidebars;
if (fs.existsSync(CWD + "/sidebars.json")) { if (fs.existsSync(CWD + '/sidebars.json')) {
allSidebars = require(CWD + "/sidebars.json"); allSidebars = require(CWD + '/sidebars.json');
} else { } else {
allSidebars = {}; allSidebars = {};
} }
@ -76,7 +72,7 @@ function readSidebar() {
previous: previous, previous: previous,
next: next, next: next,
sidebar: sidebar, sidebar: sidebar,
category: categoryOrder[i] category: categoryOrder[i],
}; };
} }
}); });
@ -85,19 +81,19 @@ function readSidebar() {
// split markdown header // split markdown header
function splitHeader(content) { function splitHeader(content) {
const lines = content.split("\n"); const lines = content.split('\n');
if (lines[0] !== "---") { if (lines[0] !== '---') {
return {}; return {};
} }
let i = 1; let i = 1;
for (; i < lines.length - 1; ++i) { for (; i < lines.length - 1; ++i) {
if (lines[i] === "---") { if (lines[i] === '---') {
break; break;
} }
} }
return { return {
header: lines.slice(1, i + 1).join("\n"), header: lines.slice(1, i + 1).join('\n'),
content: lines.slice(i + 1).join("\n") content: lines.slice(i + 1).join('\n'),
}; };
} }
@ -106,31 +102,33 @@ function extractMetadata(content) {
const metadata = {}; const metadata = {};
const both = splitHeader(content); const both = splitHeader(content);
if (Object.keys(both).length === 0) { if (Object.keys(both).length === 0) {
return { metadata, rawContent: content }; return {metadata, rawContent: content};
} }
const lines = both.header.split("\n"); const lines = both.header.split('\n');
for (let i = 0; i < lines.length - 1; ++i) { for (let i = 0; i < lines.length - 1; ++i) {
const keyvalue = lines[i].split(":"); const keyvalue = lines[i].split(':');
const key = keyvalue[0].trim(); const key = keyvalue[0].trim();
let value = keyvalue let value = keyvalue
.slice(1) .slice(1)
.join(":") .join(':')
.trim(); .trim();
try { try {
value = JSON.parse(value); value = JSON.parse(value);
} catch (e) {} } catch (e) {}
metadata[key] = value; metadata[key] = value;
} }
return { metadata, rawContent: both.content }; return {metadata, rawContent: both.content};
} }
// process the metadata for a document found in the docs folder // process the metadata for a document found in the docs folder
function processMetadata(file) { function processMetadata(file) {
const result = extractMetadata(fs.readFileSync(file, "utf8")); const result = extractMetadata(fs.readFileSync(file, 'utf8'));
let regexSubFolder = new RegExp("/" + escapeStringRegexp(getDocsPath()) + "\/(.*)\/.*/"); let regexSubFolder = new RegExp(
'/' + escapeStringRegexp(getDocsPath()) + '/(.*)/.*/'
);
let language = "en"; let language = 'en';
const match = regexSubFolder.exec(file); const match = regexSubFolder.exec(file);
if (match) { if (match) {
language = match[1]; language = match[1];
@ -143,7 +141,7 @@ function processMetadata(file) {
if (!metadata.id) { if (!metadata.id) {
metadata.id = path.basename(file, path.extname(file)); metadata.id = path.basename(file, path.extname(file));
} }
if (metadata.id.includes("/")) { if (metadata.id.includes('/')) {
throw new Error('Document id cannot include "/".'); throw new Error('Document id cannot include "/".');
} }
if (!metadata.title) { if (!metadata.title) {
@ -151,26 +149,26 @@ function processMetadata(file) {
} }
if (languages.length === 1 && !siteConfig.useEnglishUrl) { if (languages.length === 1 && !siteConfig.useEnglishUrl) {
metadata.permalink = "docs/" + metadata.id + ".html"; metadata.permalink = 'docs/' + metadata.id + '.html';
} else { } else {
metadata.permalink = "docs/" + language + "/" + metadata.id + ".html"; metadata.permalink = 'docs/' + language + '/' + metadata.id + '.html';
} }
if (ENABLE_VERSIONING) { if (ENABLE_VERSIONING) {
metadata.version = "next"; metadata.version = 'next';
if (languages.length === 1 && !siteConfig.useEnglishUrl) { if (languages.length === 1 && !siteConfig.useEnglishUrl) {
metadata.permalink = metadata.permalink.replace("docs/", "docs/next/"); metadata.permalink = metadata.permalink.replace('docs/', 'docs/next/');
} else { } else {
metadata.permalink = metadata.permalink.replace( metadata.permalink = metadata.permalink.replace(
"docs/" + language + "/", 'docs/' + language + '/',
"docs/" + language + "/next/" 'docs/' + language + '/next/'
); );
} }
} }
// change ids previous, next // change ids previous, next
metadata.localized_id = metadata.id; metadata.localized_id = metadata.id;
metadata.id = language + "-" + metadata.id; metadata.id = language + '-' + metadata.id;
metadata.language = language; metadata.language = language;
const order = readSidebar(); const order = readSidebar();
@ -182,20 +180,20 @@ function processMetadata(file) {
if (order[id].next) { if (order[id].next) {
metadata.next_id = order[id].next; metadata.next_id = order[id].next;
metadata.next = language + "-" + order[id].next; metadata.next = language + '-' + order[id].next;
} }
if (order[id].previous) { if (order[id].previous) {
metadata.previous_id = order[id].previous; metadata.previous_id = order[id].previous;
metadata.previous = language + "-" + order[id].previous; metadata.previous = language + '-' + order[id].previous;
} }
} }
return { metadata, rawContent: rawContent }; return {metadata, rawContent: rawContent};
} }
// process metadata for all docs and save into core/metadata.js // process metadata for all docs and save into core/metadata.js
function generateMetadataDocs() { function generateMetadataDocs() {
console.log("Generating Metadata for Docs...."); console.log('Generating Metadata for Docs....');
let order; let order;
try { try {
@ -216,13 +214,13 @@ function generateMetadataDocs() {
const defaultMetadatas = {}; const defaultMetadatas = {};
// metadata for english files // metadata for english files
let files = glob.sync(CWD + "/../" + getDocsPath() + "/**"); let files = glob.sync(CWD + '/../' + getDocsPath() + '/**');
files.forEach(file => { files.forEach(file => {
let language = "en"; let language = 'en';
const extension = path.extname(file); const extension = path.extname(file);
if (extension === ".md" || extension === ".markdown") { if (extension === '.md' || extension === '.markdown') {
const res = processMetadata(file); const res = processMetadata(file);
if (!res) { if (!res) {
@ -235,36 +233,36 @@ function generateMetadataDocs() {
// these will get replaced if/when the localized file is downloaded from crowdin // these will get replaced if/when the localized file is downloaded from crowdin
enabledLanguages enabledLanguages
.filter(currentLanguage => { .filter(currentLanguage => {
return currentLanguage != "en"; return currentLanguage != 'en';
}) })
.map(currentLanguage => { .map(currentLanguage => {
let baseMetadata = Object.assign({}, metadata); let baseMetadata = Object.assign({}, metadata);
baseMetadata["id"] = baseMetadata["id"] baseMetadata['id'] = baseMetadata['id']
.toString() .toString()
.replace(/^en-/, currentLanguage + "-"); .replace(/^en-/, currentLanguage + '-');
if (baseMetadata["permalink"]) if (baseMetadata['permalink'])
baseMetadata["permalink"] = baseMetadata["permalink"] baseMetadata['permalink'] = baseMetadata['permalink']
.toString() .toString()
.replace(/^docs\/en\//, "docs/" + currentLanguage + "/"); .replace(/^docs\/en\//, 'docs/' + currentLanguage + '/');
if (baseMetadata["next"]) if (baseMetadata['next'])
baseMetadata["next"] = baseMetadata["next"] baseMetadata['next'] = baseMetadata['next']
.toString() .toString()
.replace(/^en-/, currentLanguage + "-"); .replace(/^en-/, currentLanguage + '-');
if (baseMetadata["previous"]) if (baseMetadata['previous'])
baseMetadata["previous"] = baseMetadata["previous"] baseMetadata['previous'] = baseMetadata['previous']
.toString() .toString()
.replace(/^en-/, currentLanguage + "-"); .replace(/^en-/, currentLanguage + '-');
baseMetadata["language"] = currentLanguage; baseMetadata['language'] = currentLanguage;
defaultMetadatas[baseMetadata["id"]] = baseMetadata; defaultMetadatas[baseMetadata['id']] = baseMetadata;
}); });
Object.assign(metadatas, defaultMetadatas); Object.assign(metadatas, defaultMetadatas);
} }
}); });
// metadata for non-english docs // metadata for non-english docs
files = glob.sync(CWD + "/translated_docs/**"); files = glob.sync(CWD + '/translated_docs/**');
files.forEach(file => { files.forEach(file => {
let language = "en"; let language = 'en';
const match = regexSubFolder.exec(file); const match = regexSubFolder.exec(file);
if (match) { if (match) {
language = match[1]; language = match[1];
@ -276,7 +274,7 @@ function generateMetadataDocs() {
const extension = path.extname(file); const extension = path.extname(file);
if (extension === ".md" || extension === ".markdown") { if (extension === '.md' || extension === '.markdown') {
const res = processMetadata(file); const res = processMetadata(file);
if (!res) { if (!res) {
return; return;
@ -295,17 +293,17 @@ function generateMetadataDocs() {
metadata.category = order[id].category; metadata.category = order[id].category;
if (order[id].next) { if (order[id].next) {
metadata.next_id = order[id].next.replace( metadata.next_id = order[id].next.replace(
"version-" + metadata.version + "-", 'version-' + metadata.version + '-',
"" ''
); );
metadata.next = metadata.language + "-" + order[id].next; metadata.next = metadata.language + '-' + order[id].next;
} }
if (order[id].previous) { if (order[id].previous) {
metadata.previous_id = order[id].previous.replace( metadata.previous_id = order[id].previous.replace(
"version-" + metadata.version + "-", 'version-' + metadata.version + '-',
"" ''
); );
metadata.previous = metadata.language + "-" + order[id].previous; metadata.previous = metadata.language + '-' + order[id].previous;
} }
} }
metadatas[metadata.id] = metadata; metadatas[metadata.id] = metadata;
@ -319,7 +317,7 @@ function generateMetadataDocs() {
metadatas[metadata].previous_title = metadatas[metadata].previous_title =
metadatas[metadatas[metadata].previous].title; metadatas[metadatas[metadata].previous].title;
} else { } else {
metadatas[metadata].previous_title = "Previous"; metadatas[metadata].previous_title = 'Previous';
} }
} }
if (metadatas[metadata].next) { if (metadatas[metadata].next) {
@ -327,19 +325,19 @@ function generateMetadataDocs() {
metadatas[metadata].next_title = metadatas[metadata].next_title =
metadatas[metadatas[metadata].next].title; metadatas[metadatas[metadata].next].title;
} else { } else {
metadatas[metadata].next_title = "Next"; metadatas[metadata].next_title = 'Next';
} }
} }
}); });
fs.writeFileSync( fs.writeFileSync(
__dirname + "/../core/metadata.js", __dirname + '/../core/metadata.js',
"/**\n" + '/**\n' +
" * @generated\n" + ' * @generated\n' +
" */\n" + ' */\n' +
"module.exports = " + 'module.exports = ' +
JSON.stringify(metadatas, null, 2) + JSON.stringify(metadatas, null, 2) +
";" ';'
); );
} }
@ -347,11 +345,11 @@ function generateMetadataDocs() {
function generateMetadataBlog() { function generateMetadataBlog() {
const metadatas = []; const metadatas = [];
let files = glob.sync(CWD + "/blog/**/*.*"); let files = glob.sync(CWD + '/blog/**/*.*');
if (!files || files.length == 0) { if (!files || files.length == 0) {
console.error( console.error(
`${chalk.yellow( `${chalk.yellow(
CWD + "/blog/ appears to be empty" CWD + '/blog/ appears to be empty'
)} Make sure you've put your blog files in your Docusaurus 'website' folder.` )} Make sure you've put your blog files in your Docusaurus 'website' folder.`
); );
} }
@ -360,7 +358,7 @@ function generateMetadataBlog() {
.reverse() .reverse()
.forEach(file => { .forEach(file => {
const extension = path.extname(file); const extension = path.extname(file);
if (extension !== ".md" && extension !== ".markdown") { if (extension !== '.md' && extension !== '.markdown') {
return; return;
} }
// Transform // Transform
@ -369,16 +367,14 @@ function generateMetadataBlog() {
// 2015/08/13/blog-post-name-0-5.html // 2015/08/13/blog-post-name-0-5.html
const filePath = path const filePath = path
.basename(file) .basename(file)
.replace("-", "/") .replace('-', '/')
.replace("-", "/") .replace('-', '/')
.replace("-", "/") .replace('-', '/')
.replace(/\.md$/, ".html"); .replace(/\.md$/, '.html');
const result = extractMetadata( const result = extractMetadata(fs.readFileSync(file, {encoding: 'utf8'}));
fs.readFileSync(file, { encoding: "utf8" })
);
const rawContent = result.rawContent; const rawContent = result.rawContent;
const metadata = Object.assign( const metadata = Object.assign(
{ path: filePath, content: rawContent }, {path: filePath, content: rawContent},
result.metadata result.metadata
); );
@ -388,27 +384,27 @@ function generateMetadataBlog() {
let filePathDateArr = path let filePathDateArr = path
.basename(file) .basename(file)
.toString() .toString()
.split("-"); .split('-');
metadata.date = new Date( metadata.date = new Date(
filePathDateArr[0] + filePathDateArr[0] +
"-" + '-' +
filePathDateArr[1] + filePathDateArr[1] +
"-" + '-' +
filePathDateArr[2] + filePathDateArr[2] +
"T06:00:00.000Z" 'T06:00:00.000Z'
); );
metadatas.push(metadata); metadatas.push(metadata);
}); });
fs.writeFileSync( fs.writeFileSync(
__dirname + "/../core/MetadataBlog.js", __dirname + '/../core/MetadataBlog.js',
"/**\n" + '/**\n' +
" * @generated\n" + ' * @generated\n' +
" */\n" + ' */\n' +
"module.exports = " + 'module.exports = ' +
JSON.stringify(metadatas, null, 2) + JSON.stringify(metadatas, null, 2) +
";" ';'
); );
} }
@ -418,5 +414,5 @@ module.exports = {
extractMetadata, extractMetadata,
processMetadata, processMetadata,
generateMetadataDocs, generateMetadataDocs,
generateMetadataBlog generateMetadataBlog,
}; };

View file

@ -7,30 +7,30 @@
*/ */
function execute(port) { function execute(port) {
const extractTranslations = require("../write-translations.js"); const extractTranslations = require('../write-translations.js');
const translation = require("./translation.js"); const translation = require('./translation.js');
const express = require("express"); const express = require('express');
const React = require("react"); const React = require('react');
const request = require("request"); const request = require('request');
const renderToStaticMarkup = require("react-dom/server").renderToStaticMarkup; const renderToStaticMarkup = require('react-dom/server').renderToStaticMarkup;
const fs = require("fs-extra"); const fs = require('fs-extra');
const os = require("os"); const os = require('os');
const path = require("path"); const path = require('path');
const toSlug = require("../core/toSlug.js"); const toSlug = require('../core/toSlug.js');
const mkdirp = require("mkdirp"); const mkdirp = require('mkdirp');
const glob = require("glob"); const glob = require('glob');
const chalk = require("chalk"); const chalk = require('chalk');
const translate = require("./translate.js"); const translate = require('./translate.js');
const versionFallback = require("./versionFallback"); const versionFallback = require('./versionFallback');
const feed = require("./feed.js"); const feed = require('./feed.js');
const sitemap = require("./sitemap.js"); const sitemap = require('./sitemap.js');
// const sitemap = require("sitemap"); // const sitemap = require("sitemap");
const CWD = process.cwd(); const CWD = process.cwd();
const ENABLE_TRANSLATION = fs.existsSync(CWD + "/languages.js"); const ENABLE_TRANSLATION = fs.existsSync(CWD + '/languages.js');
const ENABLE_VERSIONING = fs.existsSync(CWD + "/versions.json"); const ENABLE_VERSIONING = fs.existsSync(CWD + '/versions.json');
// remove a module and child modules from require cache, so server does not have // remove a module and child modules from require cache, so server does not have
// to be restarted // to be restarted
@ -56,39 +56,39 @@ function execute(port) {
/****************************************************************************/ /****************************************************************************/
let readMetadata = require("./readMetadata.js"); let readMetadata = require('./readMetadata.js');
let Metadata; let Metadata;
let MetadataBlog; let MetadataBlog;
let siteConfig; let siteConfig;
function reloadMetadata() { function reloadMetadata() {
removeModuleAndChildrenFromCache("./readMetadata.js"); removeModuleAndChildrenFromCache('./readMetadata.js');
readMetadata.generateMetadataDocs(); readMetadata.generateMetadataDocs();
removeModuleAndChildrenFromCache("../core/metadata.js"); removeModuleAndChildrenFromCache('../core/metadata.js');
Metadata = require("../core/metadata.js"); Metadata = require('../core/metadata.js');
} }
function reloadMetadataBlog() { function reloadMetadataBlog() {
if (fs.existsSync(__dirname + "/../core/MetadataBlog.js")) { if (fs.existsSync(__dirname + '/../core/MetadataBlog.js')) {
removeModuleAndChildrenFromCache("../core/MetadataBlog.js"); removeModuleAndChildrenFromCache('../core/MetadataBlog.js');
fs.removeSync(__dirname + "/../core/MetadataBlog.js"); fs.removeSync(__dirname + '/../core/MetadataBlog.js');
} }
readMetadata.generateMetadataBlog(); readMetadata.generateMetadataBlog();
MetadataBlog = require("../core/MetadataBlog.js"); MetadataBlog = require('../core/MetadataBlog.js');
} }
function reloadSiteConfig() { function reloadSiteConfig() {
removeModuleAndChildrenFromCache(CWD + "/siteConfig.js"); removeModuleAndChildrenFromCache(CWD + '/siteConfig.js');
siteConfig = require(CWD + "/siteConfig.js"); siteConfig = require(CWD + '/siteConfig.js');
if (siteConfig.highlight && siteConfig.highlight.hljs) { if (siteConfig.highlight && siteConfig.highlight.hljs) {
siteConfig.highlight.hljs(require("highlight.js")); siteConfig.highlight.hljs(require('highlight.js'));
} }
} }
/****************************************************************************/ /****************************************************************************/
const TABLE_OF_CONTENTS_TOKEN = "<AUTOGENERATED_TABLE_OF_CONTENTS>"; const TABLE_OF_CONTENTS_TOKEN = '<AUTOGENERATED_TABLE_OF_CONTENTS>';
const insertTableOfContents = rawContent => { const insertTableOfContents = rawContent => {
const regexp = /\n###\s+(`.*`.*)\n/g; const regexp = /\n###\s+(`.*`.*)\n/g;
@ -100,7 +100,7 @@ function execute(port) {
const tableOfContents = headers const tableOfContents = headers
.map(header => ` - [${header}](#${toSlug(header)})`) .map(header => ` - [${header}](#${toSlug(header)})`)
.join("\n"); .join('\n');
return rawContent.replace(TABLE_OF_CONTENTS_TOKEN, tableOfContents); return rawContent.replace(TABLE_OF_CONTENTS_TOKEN, tableOfContents);
}; };
@ -121,7 +121,7 @@ function execute(port) {
/****************************************************************************/ /****************************************************************************/
console.log("server.js triggered..."); console.log('server.js triggered...');
reloadMetadata(); reloadMetadata();
reloadMetadataBlog(); reloadMetadataBlog();
@ -132,7 +132,7 @@ function execute(port) {
const app = express(); const app = express();
app.get(/docs\/.*html$/, (req, res, next) => { app.get(/docs\/.*html$/, (req, res, next) => {
let url = req.path.toString().replace(siteConfig.baseUrl, ""); let 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
let links = {}; let links = {};
@ -146,15 +146,15 @@ function execute(port) {
const mdToHtml = {}; const mdToHtml = {};
Object.keys(Metadata).forEach(id => { Object.keys(Metadata).forEach(id => {
const metadata = Metadata[id]; const metadata = Metadata[id];
if (metadata.language !== "en" || metadata.original_id) { if (metadata.language !== 'en' || metadata.original_id) {
return; return;
} }
let htmlLink = let htmlLink =
siteConfig.baseUrl + metadata.permalink.replace("/next/", "/"); siteConfig.baseUrl + metadata.permalink.replace('/next/', '/');
if (htmlLink.includes("/docs/en/")) { if (htmlLink.includes('/docs/en/')) {
htmlLink = htmlLink.replace("/docs/en/", "/docs/en/VERSION/"); htmlLink = htmlLink.replace('/docs/en/', '/docs/en/VERSION/');
} else { } else {
htmlLink = htmlLink.replace("/docs/", "/docs/VERSION/"); htmlLink = htmlLink.replace('/docs/', '/docs/VERSION/');
} }
mdToHtml[metadata.source] = htmlLink; mdToHtml[metadata.source] = htmlLink;
}); });
@ -169,18 +169,19 @@ function execute(port) {
// determine what file to use according to its id // determine what file to use according to its id
let file; let file;
if (metadata.original_id) { if (metadata.original_id) {
if (ENABLE_TRANSLATION && metadata.language !== "en") { if (ENABLE_TRANSLATION && metadata.language !== 'en') {
file = file =
CWD + "/translated_docs/" + metadata.language + "/" + metadata.source; CWD + '/translated_docs/' + metadata.language + '/' + metadata.source;
} else { } else {
file = CWD + "/versioned_docs/" + metadata.source; file = CWD + '/versioned_docs/' + metadata.source;
} }
} else { } else {
if (metadata.language === "en") { if (metadata.language === 'en') {
file = CWD + "/../" + readMetadata.getDocsPath() + "/" + metadata.source; file =
CWD + '/../' + readMetadata.getDocsPath() + '/' + metadata.source;
} else { } else {
file = file =
CWD + "/translated_docs/" + metadata.language + "/" + metadata.source; CWD + '/translated_docs/' + metadata.language + '/' + metadata.source;
} }
} }
@ -189,7 +190,7 @@ function execute(port) {
return; return;
} }
let rawContent = readMetadata.extractMetadata(fs.readFileSync(file, "utf8")) let rawContent = readMetadata.extractMetadata(fs.readFileSync(file, 'utf8'))
.rawContent; .rawContent;
// generate table of contents if appropriate // generate table of contents if appropriate
@ -200,46 +201,46 @@ function execute(port) {
let latestVersion; let latestVersion;
if (ENABLE_VERSIONING) { if (ENABLE_VERSIONING) {
latestVersion = JSON.parse( latestVersion = JSON.parse(
fs.readFileSync(CWD + "/versions.json", "utf8") fs.readFileSync(CWD + '/versions.json', 'utf8')
)[0]; )[0];
} }
// 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(function(key, index) { Object.keys(mdToHtml).forEach(function(key, index) {
let link = mdToHtml[key]; let link = mdToHtml[key];
link = link.replace("/en/", "/" + language + "/"); link = link.replace('/en/', '/' + language + '/');
link = link.replace( link = link.replace(
"/VERSION/", '/VERSION/',
metadata.version && metadata.version !== latestVersion metadata.version && metadata.version !== latestVersion
? "/" + metadata.version + "/" ? '/' + metadata.version + '/'
: "/" : '/'
); );
// replace relative links without "./" // replace relative links without "./"
rawContent = rawContent.replace( rawContent = rawContent.replace(
new RegExp("\\]\\(" + key, "g"), new RegExp('\\]\\(' + key, 'g'),
"](" + link '](' + link
); );
// replace relative links with "./" // replace relative links with "./"
rawContent = rawContent.replace( rawContent = rawContent.replace(
new RegExp("\\]\\(\\./" + key, "g"), new RegExp('\\]\\(\\./' + key, 'g'),
"](" + link '](' + link
); );
}); });
// replace any relative links to static assets to absolute links // replace any relative links to static assets to absolute links
rawContent = rawContent.replace( rawContent = rawContent.replace(
/\]\(assets\//g, /\]\(assets\//g,
"](" + siteConfig.baseUrl + "docs/assets/" '](' + siteConfig.baseUrl + 'docs/assets/'
); );
removeModuleAndChildrenFromCache("../core/DocsLayout.js"); removeModuleAndChildrenFromCache('../core/DocsLayout.js');
const DocsLayout = require("../core/DocsLayout.js"); const DocsLayout = require('../core/DocsLayout.js');
let Doc; let Doc;
if (metadata.layout && siteConfig.layouts[metadata.layout]) { if (metadata.layout && siteConfig.layouts[metadata.layout]) {
Doc = siteConfig.layouts[metadata.layout]({ Doc = siteConfig.layouts[metadata.layout]({
React, React,
MarkdownBlock: require("../core/MarkdownBlock.js") MarkdownBlock: require('../core/MarkdownBlock.js'),
}); });
} }
@ -256,38 +257,38 @@ function execute(port) {
res.send(renderToStaticMarkup(docComp)); res.send(renderToStaticMarkup(docComp));
}); });
app.get("/sitemap.xml", function(req, res) { app.get('/sitemap.xml', function(req, res) {
res.set("Content-Type", "application/xml"); res.set('Content-Type', 'application/xml');
sitemap(xml => { sitemap(xml => {
res.send(xml); res.send(xml);
}); });
}); });
app.get(/blog\/.*xml$/, (req, res) => { app.get(/blog\/.*xml$/, (req, res) => {
res.set("Content-Type", "application/rss+xml"); res.set('Content-Type', 'application/rss+xml');
let parts = req.path.toString().split("blog/"); let parts = req.path.toString().split('blog/');
if (parts[1].toLowerCase() == "atom.xml") { if (parts[1].toLowerCase() == 'atom.xml') {
res.send(feed("atom")); res.send(feed('atom'));
return; return;
} }
res.send(feed("rss")); res.send(feed('rss'));
}); });
app.get(/blog\/.*xml$/, (req, res) => { app.get(/blog\/.*xml$/, (req, res) => {
res.set("Content-Type", "application/rss+xml"); res.set('Content-Type', 'application/rss+xml');
let parts = req.path.toString().split("blog/"); let parts = req.path.toString().split('blog/');
if (parts[1].toLowerCase() == "atom.xml") { if (parts[1].toLowerCase() == 'atom.xml') {
res.send(feed("atom")); res.send(feed('atom'));
return; return;
} }
res.send(feed("rss")); res.send(feed('rss'));
}); });
// handle all requests for blog pages and posts // handle all requests for blog pages and posts
app.get(/blog\/.*html$/, (req, res) => { app.get(/blog\/.*html$/, (req, res) => {
// generate all of the blog pages // generate all of the blog pages
removeModuleAndChildrenFromCache("../core/BlogPageLayout.js"); removeModuleAndChildrenFromCache('../core/BlogPageLayout.js');
const BlogPageLayout = require("../core/BlogPageLayout.js"); const BlogPageLayout = require('../core/BlogPageLayout.js');
const blogPages = {}; const blogPages = {};
// make blog pages with 10 posts per page // make blog pages with 10 posts per page
const perPage = 10; const perPage = 10;
@ -296,8 +297,8 @@ function execute(port) {
page < Math.ceil(MetadataBlog.length / perPage); page < Math.ceil(MetadataBlog.length / perPage);
page++ page++
) { ) {
let language = "en"; let language = 'en';
const metadata = { page: page, perPage: perPage }; const metadata = {page: page, perPage: perPage};
const blogPageComp = ( const blogPageComp = (
<BlogPageLayout <BlogPageLayout
metadata={metadata} metadata={metadata}
@ -307,46 +308,46 @@ function execute(port) {
); );
const str = renderToStaticMarkup(blogPageComp); const str = renderToStaticMarkup(blogPageComp);
let path = (page > 0 ? "page" + (page + 1) : "") + "/index.html"; let path = (page > 0 ? 'page' + (page + 1) : '') + '/index.html';
blogPages[path] = str; blogPages[path] = str;
} }
let parts = req.path.toString().split("blog/"); let parts = req.path.toString().split('blog/');
// send corresponding blog page if appropriate // send corresponding blog page if appropriate
if (parts[1] === "index.html") { if (parts[1] === 'index.html') {
res.send(blogPages["/index.html"]); res.send(blogPages['/index.html']);
} else if (parts[1].endsWith("/index.html")) { } else if (parts[1].endsWith('/index.html')) {
res.send(blogPages[parts[1]]); res.send(blogPages[parts[1]]);
} else if (parts[1].match(/page([0-9]+)/)) { } else if (parts[1].match(/page([0-9]+)/)) {
if (parts[1].endsWith("/")) { if (parts[1].endsWith('/')) {
res.send(blogPages[parts[1] + "index.html"]); res.send(blogPages[parts[1] + 'index.html']);
} else { } else {
res.send(blogPages[parts[1] + "/index.html"]); res.send(blogPages[parts[1] + '/index.html']);
} }
} else { } else {
// else send corresponding blog post // else send corresponding blog post
let file = parts[1]; let file = parts[1];
file = file.replace(/\.html$/, ".md"); file = file.replace(/\.html$/, '.md');
file = file.replace(new RegExp("/", "g"), "-"); file = file.replace(new RegExp('/', 'g'), '-');
file = CWD + "/blog/" + file; file = CWD + '/blog/' + file;
const result = readMetadata.extractMetadata( const result = readMetadata.extractMetadata(
fs.readFileSync(file, { encoding: "utf8" }) fs.readFileSync(file, {encoding: 'utf8'})
); );
let rawContent = result.rawContent; let rawContent = result.rawContent;
rawContent = rawContent.replace( rawContent = rawContent.replace(
/\]\(assets\//g, /\]\(assets\//g,
"](" + siteConfig.baseUrl + "blog/assets/" '](' + siteConfig.baseUrl + 'blog/assets/'
); );
const metadata = Object.assign( const metadata = Object.assign(
{ path: req.path.toString().split("blog/")[1], content: rawContent }, {path: req.path.toString().split('blog/')[1], content: rawContent},
result.metadata result.metadata
); );
metadata.id = metadata.title; metadata.id = metadata.title;
let language = "en"; let language = 'en';
removeModuleAndChildrenFromCache("../core/BlogPostLayout.js"); removeModuleAndChildrenFromCache('../core/BlogPostLayout.js');
const BlogPostLayout = require("../core/BlogPostLayout.js"); const BlogPostLayout = require('../core/BlogPostLayout.js');
const blogPostComp = ( const blogPostComp = (
<BlogPostLayout <BlogPostLayout
@ -361,44 +362,44 @@ function execute(port) {
}); });
// handle all other main pages // handle all other main pages
app.get("*.html", (req, res, next) => { app.get('*.html', (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 = CWD + "/pages/" + htmlFile; htmlFile = CWD + '/pages/' + htmlFile;
if ( if (
fs.existsSync(htmlFile) || fs.existsSync(htmlFile) ||
fs.existsSync( fs.existsSync(
(htmlFile = htmlFile.replace( (htmlFile = htmlFile.replace(
path.basename(htmlFile), path.basename(htmlFile),
"en/" + path.basename(htmlFile) 'en/' + path.basename(htmlFile)
)) ))
) )
) { ) {
res.send(fs.readFileSync(htmlFile, { encoding: "utf8" })); res.send(fs.readFileSync(htmlFile, {encoding: 'utf8'}));
return; return;
} }
// look for user provided react file either in specified path or in path for english files // look for user provided react file either in specified path or in path for english files
let file = req.path.toString().replace(/\.html$/, ".js"); let file = req.path.toString().replace(/\.html$/, '.js');
file = file.replace(siteConfig.baseUrl, ""); file = file.replace(siteConfig.baseUrl, '');
let userFile = CWD + "/pages/" + file; let userFile = CWD + '/pages/' + file;
let language = "en"; let language = 'en';
const regexLang = /(.*)\/.*\.html$/; const regexLang = /(.*)\/.*\.html$/;
const match = regexLang.exec(req.path); const match = regexLang.exec(req.path);
const parts = match[1].split("/"); const parts = match[1].split('/');
const enabledLangTags = []; const enabledLangTags = [];
for (let i = 0; i < translation["languages"].length; i++) { for (let i = 0; i < translation['languages'].length; i++) {
enabledLangTags.push(translation["languages"][i].tag); enabledLangTags.push(translation['languages'][i].tag);
} }
for (let i = 0; i < parts.length; i++) { for (let i = 0; i < parts.length; i++) {
if (enabledLangTags.indexOf(parts[i]) !== -1) { if (enabledLangTags.indexOf(parts[i]) !== -1) {
language = parts[i]; language = parts[i];
} }
} }
let englishFile = CWD + "/pages/" + file; let englishFile = CWD + '/pages/' + file;
if (language !== "en") { if (language !== 'en') {
englishFile = englishFile.replace("/" + language + "/", "/en/"); englishFile = englishFile.replace('/' + language + '/', '/en/');
} }
// check for: a file for the page, an english file for page with unspecified language, or an // check for: a file for the page, an english file for page with unspecified language, or an
@ -408,26 +409,26 @@ function execute(port) {
fs.existsSync( fs.existsSync(
(userFile = userFile.replace( (userFile = userFile.replace(
path.basename(userFile), path.basename(userFile),
"en/" + path.basename(userFile) 'en/' + path.basename(userFile)
)) ))
) || ) ||
fs.existsSync((userFile = englishFile)) fs.existsSync((userFile = englishFile))
) { ) {
// copy into docusaurus so require paths work // copy into docusaurus so require paths work
let parts = userFile.split("pages/"); let parts = userFile.split('pages/');
let tempFile = __dirname + "/../pages/" + parts[1]; let tempFile = __dirname + '/../pages/' + parts[1];
tempFile = tempFile.replace( tempFile = tempFile.replace(
path.basename(file), path.basename(file),
"temp" + path.basename(file) 'temp' + path.basename(file)
); );
mkdirp.sync(tempFile.replace(new RegExp("/[^/]*$"), "")); mkdirp.sync(tempFile.replace(new RegExp('/[^/]*$'), ''));
fs.copySync(userFile, tempFile); fs.copySync(userFile, tempFile);
// render into a string // render into a string
removeModuleAndChildrenFromCache(tempFile); removeModuleAndChildrenFromCache(tempFile);
const ReactComp = require(tempFile); const ReactComp = require(tempFile);
removeModuleAndChildrenFromCache("../core/Site.js"); removeModuleAndChildrenFromCache('../core/Site.js');
const Site = require("../core/Site.js"); const Site = require('../core/Site.js');
translate.setLanguage(language); translate.setLanguage(language);
const str = renderToStaticMarkup( const str = renderToStaticMarkup(
<Site language={language} config={siteConfig}> <Site language={language} config={siteConfig}>
@ -448,18 +449,18 @@ function execute(port) {
app.get(/main\.css$/, (req, res) => { app.get(/main\.css$/, (req, res) => {
const mainCssPath = const mainCssPath =
__dirname + __dirname +
"/../static/" + '/../static/' +
req.path.toString().replace(siteConfig.baseUrl, "/"); req.path.toString().replace(siteConfig.baseUrl, '/');
let cssContent = fs.readFileSync(mainCssPath, { encoding: "utf8" }); let cssContent = fs.readFileSync(mainCssPath, {encoding: 'utf8'});
let files = glob.sync(CWD + "/static/**/*.css"); let files = glob.sync(CWD + '/static/**/*.css');
files.forEach(file => { files.forEach(file => {
if (isSeparateCss(file)) { if (isSeparateCss(file)) {
return; return;
} }
cssContent = cssContent =
cssContent + "\n" + fs.readFileSync(file, { encoding: "utf8" }); cssContent + '\n' + fs.readFileSync(file, {encoding: 'utf8'});
}); });
if ( if (
@ -469,14 +470,14 @@ function execute(port) {
) { ) {
console.error( console.error(
`${chalk.yellow( `${chalk.yellow(
"Missing color configuration." 'Missing color configuration.'
)} Make sure siteConfig.colors includes primaryColor and secondaryColor fields.` )} Make sure siteConfig.colors includes primaryColor and secondaryColor fields.`
); );
} }
Object.keys(siteConfig.colors).forEach(key => { Object.keys(siteConfig.colors).forEach(key => {
const color = siteConfig.colors[key]; const color = siteConfig.colors[key];
cssContent = cssContent.replace(new RegExp("\\$" + key, "g"), color); cssContent = cssContent.replace(new RegExp('\\$' + key, 'g'), color);
}); });
res.send(cssContent); res.send(cssContent);
@ -484,22 +485,22 @@ function execute(port) {
// serve static assets from these locations // serve static assets from these locations
app.use( app.use(
siteConfig.baseUrl + "docs/assets/", siteConfig.baseUrl + 'docs/assets/',
express.static(CWD + "/../" + readMetadata.getDocsPath() + "/assets") express.static(CWD + '/../' + readMetadata.getDocsPath() + '/assets')
); );
app.use( app.use(
siteConfig.baseUrl + "blog/assets/", siteConfig.baseUrl + 'blog/assets/',
express.static(CWD + "/blog/assets") express.static(CWD + '/blog/assets')
); );
app.use(siteConfig.baseUrl, express.static(CWD + "/static")); app.use(siteConfig.baseUrl, express.static(CWD + '/static'));
app.use(siteConfig.baseUrl, express.static(__dirname + "/../static")); app.use(siteConfig.baseUrl, express.static(__dirname + '/../static'));
// "redirect" requests to pages ending with "/" or no extension so that // "redirect" requests to pages ending with "/" or no extension so that
// request to "...blog" returns same result as "...blog/index.html" // request to "...blog" returns same result as "...blog/index.html"
app.get(/\/[^\.]*\/?$/, (req, res) => { app.get(/\/[^\.]*\/?$/, (req, res) => {
if (req.path.toString().endsWith("/")) { if (req.path.toString().endsWith('/')) {
request.get( request.get(
"http://localhost:" + port + req.path + "index.html", 'http://localhost:' + port + req.path + 'index.html',
(err, response, body) => { (err, response, body) => {
if (!err) { if (!err) {
res.send(body); res.send(body);
@ -508,7 +509,7 @@ function execute(port) {
); );
} else { } else {
request.get( request.get(
"http://localhost:" + port + req.path + "/index.html", 'http://localhost:' + port + req.path + '/index.html',
(err, response, body) => { (err, response, body) => {
if (!err) { if (!err) {
res.send(body); res.send(body);
@ -519,8 +520,8 @@ function execute(port) {
}); });
app.listen(port); app.listen(port);
console.log("listening on port: " + port); console.log('listening on port: ' + port);
console.log("Open http://localhost:" + port + "/"); console.log('Open http://localhost:' + port + '/');
} }
module.exports = execute; module.exports = execute;

View file

@ -5,21 +5,21 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const fs = require("fs-extra"); const fs = require('fs-extra');
const path = require("path"); const path = require('path');
const os = require("os"); const os = require('os');
const Feed = require("feed"); const Feed = require('feed');
const chalk = require("chalk"); const chalk = require('chalk');
const glob = require("glob"); const glob = require('glob');
const CWD = process.cwd(); const CWD = process.cwd();
const sitemap = require("sitemap"); const sitemap = require('sitemap');
const siteConfig = require(CWD + "/siteConfig.js"); const siteConfig = require(CWD + '/siteConfig.js');
const blogFolder = path.resolve("../blog/"); const blogFolder = path.resolve('../blog/');
const blogRootURL = siteConfig.url + "/blog"; const blogRootURL = siteConfig.url + '/blog';
const jestImage = siteConfig.url + siteConfig.headerIcon; const jestImage = siteConfig.url + siteConfig.headerIcon;
/****************************************************************************/ /****************************************************************************/
@ -28,32 +28,33 @@ let readMetadata;
let Metadata; let Metadata;
let MetadataBlog; let MetadataBlog;
readMetadata = require("./readMetadata.js"); readMetadata = require('./readMetadata.js');
readMetadata.generateMetadataDocs(); readMetadata.generateMetadataDocs();
Metadata = require("../core/metadata.js"); Metadata = require('../core/metadata.js');
readMetadata.generateMetadataBlog(); readMetadata.generateMetadataBlog();
MetadataBlog = require("../core/MetadataBlog.js"); MetadataBlog = require('../core/MetadataBlog.js');
/****************************************************************************/ /****************************************************************************/
module.exports = function(callback) { module.exports = function(callback) {
console.log("sitemap.js triggered..."); console.log('sitemap.js triggered...');
let urls = []; let urls = [];
let files = glob.sync(CWD + "/pages/en/**/*.js"); let files = glob.sync(CWD + '/pages/en/**/*.js');
// English-only is the default. // English-only is the default.
let enabledLanguages = [{ let enabledLanguages = [
enabled: true, {
name: "English", enabled: true,
tag: "en" name: 'English',
}]; tag: 'en',
},
];
// If we have a languages.js file, get all the enabled languages in there // If we have a languages.js file, get all the enabled languages in there
if (fs.existsSync(CWD + "/languages.js")) { if (fs.existsSync(CWD + '/languages.js')) {
let languages = require(CWD + "/languages.js"); let languages = require(CWD + '/languages.js');
enabledLanguages = languages.filter(lang => { enabledLanguages = languages.filter(lang => {
return lang.enabled == true; return lang.enabled == true;
}); });
@ -61,43 +62,50 @@ module.exports = function(callback) {
// create a url mapping to all the enabled languages files // create a url mapping to all the enabled languages files
files.map(file => { files.map(file => {
let url = file.split("/pages/en")[1]; let url = file.split('/pages/en')[1];
url = url.replace(/\.js$/, ".html"); url = url.replace(/\.js$/, '.html');
let links = enabledLanguages.map(lang => { let links = enabledLanguages.map(lang => {
let langUrl = lang.tag + url; let langUrl = lang.tag + url;
return { lang: lang.tag, url: langUrl }; return {lang: lang.tag, url: langUrl};
}); });
urls.push({ url, changefreq: "weekly", priority: 0.5, links }); urls.push({url, changefreq: 'weekly', priority: 0.5, links});
}); });
let htmlFiles = glob.sync(CWD + "/pages/**/*.html"); let htmlFiles = glob.sync(CWD + '/pages/**/*.html');
MetadataBlog.map(blog => { MetadataBlog.map(blog => {
urls.push({ urls.push({
url: "/blog/" + blog.path, url: '/blog/' + blog.path,
changefreq: "weekly", changefreq: 'weekly',
priority: 0.3 priority: 0.3,
}); });
}); });
Object.keys(Metadata).filter(key => Metadata[key].language === "en").map(key => { Object.keys(Metadata)
let doc = Metadata[key]; .filter(key => Metadata[key].language === 'en')
let links = enabledLanguages.map(lang => { .map(key => {
let langUrl = doc.permalink.replace("docs/en/", `docs/${lang.tag}/`); let doc = Metadata[key];
return { lang: lang.tag, url: langUrl }; let links = enabledLanguages.map(lang => {
let langUrl = doc.permalink.replace('docs/en/', `docs/${lang.tag}/`);
return {lang: lang.tag, url: langUrl};
});
urls.push({
url: doc.permalink,
changefreq: 'hourly',
priority: 1.0,
links,
});
}); });
urls.push({ url: doc.permalink, changefreq: "hourly", priority: 1.0, links });
});
const sm = sitemap.createSitemap({ const sm = sitemap.createSitemap({
hostname: siteConfig.url, hostname: siteConfig.url,
cacheTime: 600 * 1000, // 600 sec - cache purge period cacheTime: 600 * 1000, // 600 sec - cache purge period
urls: urls urls: urls,
}); });
sm.toXML((err, xml) => { sm.toXML((err, xml) => {
if (err) { if (err) {
return "An error has occured."; return 'An error has occured.';
} }
callback(xml); callback(xml);
}); });

View file

@ -8,40 +8,40 @@
/* replaces translate tags with calls to translate function */ /* replaces translate tags with calls to translate function */
module.exports = function translatePlugin(babel) { module.exports = function translatePlugin(babel) {
const { types: t } = babel; const {types: t} = babel;
return { return {
visitor: { visitor: {
JSXElement(path) { JSXElement(path) {
if (path.node.openingElement.name.name !== "translate") { if (path.node.openingElement.name.name !== 'translate') {
return; return;
} }
/* assume translate element only has one child which is the text */ /* assume translate element only has one child which is the text */
const text = path.node.children[0].value.trim().replace(/\s+/g, " "); const text = path.node.children[0].value.trim().replace(/\s+/g, ' ');
let description = "no description given"; let description = 'no description given';
const attributes = path.node.openingElement.attributes; const attributes = path.node.openingElement.attributes;
for (let i = 0; i < attributes.length; i++) { for (let i = 0; i < attributes.length; i++) {
if (attributes[i].name.name === "desc") { if (attributes[i].name.name === 'desc') {
description = attributes[i].value.value; description = attributes[i].value.value;
} }
} }
/* use an expression container if inside a jsxelement */ /* use an expression container if inside a jsxelement */
if (path.findParent(path => true).node.type === "JSXElement") { if (path.findParent(path => true).node.type === 'JSXElement') {
path.replaceWith( path.replaceWith(
t.jSXExpressionContainer( t.jSXExpressionContainer(
t.callExpression(t.identifier("translate"), [ t.callExpression(t.identifier('translate'), [
t.stringLiteral(text + "|" + description) t.stringLiteral(text + '|' + description),
]) ])
) )
); );
} else { } else {
path.replaceWith( path.replaceWith(
t.callExpression(t.identifier("translate"), [ t.callExpression(t.identifier('translate'), [
t.stringLiteral(text + "|" + description) t.stringLiteral(text + '|' + description),
]) ])
); );
} }
} },
} },
}; };
}; };

View file

@ -5,21 +5,21 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const translation = require("./translation.js"); const translation = require('./translation.js');
let language = "en"; let language = 'en';
/* handle escaped characters that get converted into json strings */ /* handle escaped characters that get converted into json strings */
function parseEscapeSequences(str) { function parseEscapeSequences(str) {
return str return str
.replace(new RegExp("\\\\n", "g"), "\n") .replace(new RegExp('\\\\n', 'g'), '\n')
.replace(new RegExp("\\\\b", "g"), "\b") .replace(new RegExp('\\\\b', 'g'), '\b')
.replace(new RegExp("\\\\f", "g"), "\f") .replace(new RegExp('\\\\f', 'g'), '\f')
.replace(new RegExp("\\\\r", "g"), "\r") .replace(new RegExp('\\\\r', 'g'), '\r')
.replace(new RegExp("\\\\t", "g"), "\t") .replace(new RegExp('\\\\t', 'g'), '\t')
.replace(new RegExp("\\\\'", "g"), "'") .replace(new RegExp("\\\\'", 'g'), "'")
.replace(new RegExp('\\\\"', "g"), '"') .replace(new RegExp('\\\\"', 'g'), '"')
.replace(new RegExp("\\\\", "g"), "\\"); .replace(new RegExp('\\\\', 'g'), '\\');
} }
function setLanguage(lang) { function setLanguage(lang) {
@ -29,14 +29,14 @@ function setLanguage(lang) {
function translate(str) { function translate(str) {
if ( if (
!translation[language] || !translation[language] ||
!translation[language]["pages-strings"] || !translation[language]['pages-strings'] ||
!translation[language]["pages-strings"][str] !translation[language]['pages-strings'][str]
) { ) {
// if a translated string doesn't exist, but english does then fallback // if a translated string doesn't exist, but english does then fallback
if ( if (
translation["en"] && translation['en'] &&
translation["en"]["pages-strings"] && translation['en']['pages-strings'] &&
translation["en"]["pages-strings"][str] translation['en']['pages-strings'][str]
) { ) {
console.error( console.error(
"Could not find a string translation in '" + "Could not find a string translation in '" +
@ -46,7 +46,7 @@ function translate(str) {
"'. Using English version instead." "'. Using English version instead."
); );
return parseEscapeSequences(translation["en"]["pages-strings"][str]); return parseEscapeSequences(translation['en']['pages-strings'][str]);
} }
throw new Error( throw new Error(
"Text that you've identified for translation ('" + "Text that you've identified for translation ('" +
@ -54,10 +54,10 @@ function translate(str) {
"') hasn't been added to the global list in 'en.json'. To solve this problem run 'yarn write-translations'." "') hasn't been added to the global list in 'en.json'. To solve this problem run 'yarn write-translations'."
); );
} }
return parseEscapeSequences(translation[language]["pages-strings"][str]); return parseEscapeSequences(translation[language]['pages-strings'][str]);
} }
module.exports = { module.exports = {
setLanguage: setLanguage, setLanguage: setLanguage,
translate: translate translate: translate,
}; };

View file

@ -8,35 +8,35 @@
// translation object contains all translations for each string in 18n/en.json // translation object contains all translations for each string in 18n/en.json
const CWD = process.cwd(); const CWD = process.cwd();
const fs = require("fs"); const fs = require('fs');
const glob = require("glob"); const glob = require('glob');
const path = require("path"); const path = require('path');
let languages; let languages;
if (fs.existsSync(CWD + "/languages.js")) { if (fs.existsSync(CWD + '/languages.js')) {
languages = require(CWD + "/languages.js"); languages = require(CWD + '/languages.js');
} else { } else {
languages = [ languages = [
{ {
enabled: true, enabled: true,
name: "English", name: 'English',
tag: "en" tag: 'en',
} },
]; ];
} }
const enabledLanguages = languages.filter(lang => lang.enabled); const enabledLanguages = languages.filter(lang => lang.enabled);
const translation = { languages: enabledLanguages }; const translation = {languages: enabledLanguages};
const files = glob.sync(CWD + "/i18n/**"); const files = glob.sync(CWD + '/i18n/**');
const langRegex = /\/i18n\/(.*)\.json$/; const langRegex = /\/i18n\/(.*)\.json$/;
console.log("Loading translation files..."); console.log('Loading translation files...');
files.forEach(file => { files.forEach(file => {
const extension = path.extname(file); const extension = path.extname(file);
if (extension === ".json") { if (extension === '.json') {
const match = langRegex.exec(file); const match = langRegex.exec(file);
const language = match[1]; const language = match[1];
translation[language] = require(file); translation[language] = require(file);

View file

@ -6,32 +6,32 @@
*/ */
const CWD = process.cwd(); const CWD = process.cwd();
const glob = require("glob"); const glob = require('glob');
const fs = require("fs"); const fs = require('fs');
const path = require("path"); const path = require('path');
const assert = require("assert"); const assert = require('assert');
const siteConfig = require(CWD + "/siteConfig.js"); const siteConfig = require(CWD + '/siteConfig.js');
const ENABLE_TRANSLATION = fs.existsSync(CWD + "/languages.js"); const ENABLE_TRANSLATION = fs.existsSync(CWD + '/languages.js');
let versions; let versions;
if (fs.existsSync(CWD + "/versions.json")) { if (fs.existsSync(CWD + '/versions.json')) {
versions = require(CWD + "/versions.json"); versions = require(CWD + '/versions.json');
} else { } else {
versions = []; versions = [];
} }
let languages; let languages;
if (fs.existsSync(CWD + "/languages.js")) { if (fs.existsSync(CWD + '/languages.js')) {
languages = require(CWD + "/languages.js"); languages = require(CWD + '/languages.js');
} else { } else {
languages = [ languages = [
{ {
enabled: true, enabled: true,
name: "English", name: 'English',
tag: "en" tag: 'en',
} },
]; ];
} }
@ -40,16 +40,16 @@ if (fs.existsSync(CWD + "/languages.js")) {
// included to prevent cyclical dependency with readMetadata.js // included to prevent cyclical dependency with readMetadata.js
function splitHeader(content) { function splitHeader(content) {
const lines = content.split("\n"); const lines = content.split('\n');
let i = 1; let i = 1;
for (; i < lines.length - 1; ++i) { for (; i < lines.length - 1; ++i) {
if (lines[i] === "---") { if (lines[i] === '---') {
break; break;
} }
} }
return { return {
header: lines.slice(1, i + 1).join("\n"), header: lines.slice(1, i + 1).join('\n'),
content: lines.slice(i + 1).join("\n") content: lines.slice(i + 1).join('\n'),
}; };
} }
@ -59,27 +59,27 @@ function extractMetadata(content) {
const both = splitHeader(content); const both = splitHeader(content);
// if no content returned, then that means there was no header, and both.header is the content // if no content returned, then that means there was no header, and both.header is the content
if (!both.content) { if (!both.content) {
return { metadata, rawContent: both.header }; return {metadata, rawContent: both.header};
} }
const lines = both.header.split("\n"); const lines = both.header.split('\n');
for (let i = 0; i < lines.length - 1; ++i) { for (let i = 0; i < lines.length - 1; ++i) {
const keyvalue = lines[i].split(":"); const keyvalue = lines[i].split(':');
const key = keyvalue[0].trim(); const key = keyvalue[0].trim();
let value = keyvalue let value = keyvalue
.slice(1) .slice(1)
.join(":") .join(':')
.trim(); .trim();
try { try {
value = JSON.parse(value); value = JSON.parse(value);
} catch (e) {} } catch (e) {}
metadata[key] = value; metadata[key] = value;
} }
return { metadata, rawContent: both.content }; return {metadata, rawContent: both.content};
} }
/*****************************************************************/ /*****************************************************************/
const versionFolder = CWD + "/versioned_docs/"; const versionFolder = CWD + '/versioned_docs/';
// available stores doc ids of documents that are available for // available stores doc ids of documents that are available for
// each version // each version
@ -87,39 +87,47 @@ const available = {};
// versionFiles is used to keep track of what file to use with a // versionFiles is used to keep track of what file to use with a
// given version/id of a document // given version/id of a document
const versionFiles = {}; const versionFiles = {};
let files = glob.sync(versionFolder + "**"); let files = glob.sync(versionFolder + '**');
files.forEach(file => { files.forEach(file => {
const ext = path.extname(file); const ext = path.extname(file);
if (ext !== ".md" && ext !== ".markdown") { if (ext !== '.md' && ext !== '.markdown') {
return; return;
} }
const res = extractMetadata(fs.readFileSync(file, "utf8")); const res = extractMetadata(fs.readFileSync(file, 'utf8'));
const metadata = res.metadata; const metadata = res.metadata;
if (!metadata.original_id) { if (!metadata.original_id) {
console.error( console.error(
`No 'original_id' field found in ${file}. Perhaps you forgot to add it when importing prior versions of your docs?` `No 'original_id' field found in ${
file
}. Perhaps you forgot to add it when importing prior versions of your docs?`
); );
throw new Error( throw new Error(
`No 'original_id' field found in ${file}. Perhaps you forgot to add it when importing prior versions of your docs?` `No 'original_id' field found in ${
file
}. Perhaps you forgot to add it when importing prior versions of your docs?`
); );
} }
if (!metadata.id) { if (!metadata.id) {
console.error(`No 'id' field found in ${file}.`); console.error(`No 'id' field found in ${file}.`);
throw new Error(`No 'id' field found in ${file}.`); throw new Error(`No 'id' field found in ${file}.`);
} else if (metadata.id.indexOf("version-") === -1) { } else if (metadata.id.indexOf('version-') === -1) {
console.error( console.error(
`The 'id' field in ${file} is missing the expected 'version-XX-' prefix. Perhaps you forgot to add it when importing prior versions of your docs?` `The 'id' field in ${
file
} is missing the expected 'version-XX-' prefix. Perhaps you forgot to add it when importing prior versions of your docs?`
); );
throw new Error( throw new Error(
`The 'id' field in ${file} is missing the expected 'version-XX-' prefix. Perhaps you forgot to add it when importing prior versions of your docs?` `The 'id' field in ${
file
} is missing the expected 'version-XX-' prefix. Perhaps you forgot to add it when importing prior versions of your docs?`
); );
} }
if (!(metadata.original_id in available)) { if (!(metadata.original_id in available)) {
available[metadata.original_id] = new Set(); available[metadata.original_id] = new Set();
} }
const version = metadata.id.split("-")[1]; const version = metadata.id.split('-')[1];
available[metadata.original_id].add(version); available[metadata.original_id].add(version);
if (!(version in versionFiles)) { if (!(version in versionFiles)) {
@ -133,7 +141,9 @@ files.forEach(file => {
function docVersion(id, req_version) { function docVersion(id, req_version) {
if (!available[id]) { if (!available[id]) {
throw new Error( throw new Error(
`Document with id '${id}' was requested but no document with that id could be located.` `Document with id '${
id
}' was requested but no document with that id could be located.`
); );
} }
// iterate through versions until a version less than or equal to the requested // iterate through versions until a version less than or equal to the requested
@ -179,40 +189,40 @@ function diffLatestDoc(file, id) {
} }
return ( return (
extractMetadata(fs.readFileSync(latestFile, "utf8")).rawContent.trim() !== extractMetadata(fs.readFileSync(latestFile, 'utf8')).rawContent.trim() !==
extractMetadata(fs.readFileSync(file, "utf8")).rawContent.trim() extractMetadata(fs.readFileSync(file, 'utf8')).rawContent.trim()
); );
} }
// return metadata for a versioned file given the file, its version (requested), // return metadata for a versioned file given the file, its version (requested),
// the version of the file to be used, and its language // the version of the file to be used, and its language
function processVersionMetadata(file, version, useVersion, language) { function processVersionMetadata(file, version, useVersion, language) {
const metadata = extractMetadata(fs.readFileSync(file, "utf8")).metadata; const metadata = extractMetadata(fs.readFileSync(file, 'utf8')).metadata;
metadata.source = "version-" + useVersion + "/" + path.basename(file); metadata.source = 'version-' + useVersion + '/' + path.basename(file);
const latestVersion = versions[0]; const latestVersion = versions[0];
if (!ENABLE_TRANSLATION && !siteConfig.useEnglishUrl) { if (!ENABLE_TRANSLATION && !siteConfig.useEnglishUrl) {
metadata.permalink = metadata.permalink =
"docs/" + 'docs/' +
(version !== latestVersion ? version + "/" : "") + (version !== latestVersion ? version + '/' : '') +
metadata.original_id + metadata.original_id +
".html"; '.html';
} else { } else {
metadata.permalink = metadata.permalink =
"docs/" + 'docs/' +
language + language +
"/" + '/' +
(version !== latestVersion ? version + "/" : "") + (version !== latestVersion ? version + '/' : '') +
metadata.original_id + metadata.original_id +
".html"; '.html';
} }
metadata.id = metadata.id.replace( metadata.id = metadata.id.replace(
"version-" + useVersion + "-", 'version-' + useVersion + '-',
"version-" + version + "-" 'version-' + version + '-'
); );
metadata.localized_id = metadata.id; metadata.localized_id = metadata.id;
metadata.id = language + "-" + metadata.id; metadata.id = language + '-' + metadata.id;
metadata.language = language; metadata.language = language;
metadata.version = version; metadata.version = version;
@ -269,14 +279,16 @@ function sidebarVersion(req_version) {
} }
if ( if (
fs.existsSync( fs.existsSync(
CWD + "/versioned_sidebars/version-" + versions[i] + "-sidebars.json" CWD + '/versioned_sidebars/version-' + versions[i] + '-sidebars.json'
) )
) { ) {
return versions[i]; return versions[i];
} }
} }
throw new Error( throw new Error(
`No sidebar file available to use for version ${req_version}. Verify that 'version-${req_version}-sidebars.json' exists.` `No sidebar file available to use for version ${
req_version
}. Verify that 'version-${req_version}-sidebars.json' exists.`
); );
} }
@ -290,11 +302,11 @@ function diffLatestSidebar() {
const version = sidebarVersion(latest); const version = sidebarVersion(latest);
const latestSidebar = const latestSidebar =
CWD + "/versioned_sidebars/version-" + version + "-sidebars.json"; CWD + '/versioned_sidebars/version-' + version + '-sidebars.json';
if (!fs.existsSync(latestSidebar)) { if (!fs.existsSync(latestSidebar)) {
return true; return true;
} }
const currentSidebar = CWD + "/sidebars.json"; const currentSidebar = CWD + '/sidebars.json';
// if no current sidebar file, return false so no sidebar file gets copied // if no current sidebar file, return false so no sidebar file gets copied
if (!fs.existsSync(currentSidebar)) { if (!fs.existsSync(currentSidebar)) {
return false; return false;
@ -303,10 +315,10 @@ function diffLatestSidebar() {
// compare for equality between latest version sidebar with version prefixes // compare for equality between latest version sidebar with version prefixes
// stripped and current sidebar // stripped and current sidebar
return ( return (
JSON.stringify(JSON.parse(fs.readFileSync(latestSidebar, "utf8"))).replace( JSON.stringify(JSON.parse(fs.readFileSync(latestSidebar, 'utf8'))).replace(
new RegExp("version-" + version + "-", "g"), new RegExp('version-' + version + '-', 'g'),
"" ''
) !== JSON.stringify(JSON.parse(fs.readFileSync(currentSidebar, "utf8"))) ) !== JSON.stringify(JSON.parse(fs.readFileSync(currentSidebar, 'utf8')))
); );
} }
@ -319,12 +331,12 @@ function sidebarData() {
const sidebar = JSON.parse( const sidebar = JSON.parse(
fs fs
.readFileSync( .readFileSync(
CWD + "/versioned_sidebars/version-" + version + "-sidebars.json", CWD + '/versioned_sidebars/version-' + version + '-sidebars.json',
"utf8" 'utf8'
) )
.replace( .replace(
new RegExp("version-" + version + "-", "g"), new RegExp('version-' + version + '-', 'g'),
"version-" + versions[i] + "-" 'version-' + versions[i] + '-'
) )
); );
Object.assign(allSidebars, sidebar); Object.assign(allSidebars, sidebar);
@ -339,5 +351,5 @@ module.exports = {
docData, docData,
sidebarVersion, sidebarVersion,
diffLatestSidebar, diffLatestSidebar,
sidebarData sidebarData,
}; };

View file

@ -7,46 +7,43 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
require("babel-register")({ require('babel-register')({
babelrc: false, babelrc: false,
only: [__dirname, process.cwd() + "/core"], only: [__dirname, process.cwd() + '/core'],
plugins: [require("./server/translate-plugin.js")], plugins: [require('./server/translate-plugin.js')],
presets: ["react", "env"] presets: ['react', 'env'],
}); });
// For verifying port usage // For verifying port usage
const tcpPortUsed = require('tcp-port-used'); const tcpPortUsed = require('tcp-port-used');
// initial check that required files are present // initial check that required files are present
const chalk = require("chalk"); const chalk = require('chalk');
const fs = require("fs"); const fs = require('fs');
const CWD = process.cwd(); const CWD = process.cwd();
if (!fs.existsSync(CWD + "/siteConfig.js")) { if (!fs.existsSync(CWD + '/siteConfig.js')) {
console.error( console.error(
chalk.red("Error: No siteConfig.js file found in website folder!") chalk.red('Error: No siteConfig.js file found in website folder!')
); );
process.exit(1); process.exit(1);
} }
const program = require("commander"); const program = require('commander');
program.option("--port <number>", "Specify port number").parse(process.argv); program.option('--port <number>', 'Specify port number').parse(process.argv);
const port = parseInt(program.port, 10) || 3000; const port = parseInt(program.port, 10) || 3000;
console.log("Checking if port " + port + " is free..."); console.log('Checking if port ' + port + ' is free...');
tcpPortUsed.check(port, "localhost") tcpPortUsed.check(port, 'localhost').then(function(inUse) {
.then(function(inUse) {
if (inUse) { if (inUse) {
console.error( console.error(chalk.red('Port ' + port + ' is in use'));
chalk.red("Port " + port + " is in use")
);
process.exit(1); process.exit(1);
} else { } else {
console.log("Starting Docusaurus server on port " + port + "..."); console.log('Starting Docusaurus server on port ' + port + '...');
// start local server on specified port // start local server on specified port
const server = require("./server/server.js"); const server = require('./server/server.js');
server(port); server(port);
} }
}); });

View file

@ -7,36 +7,36 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const glob = require("glob"); const glob = require('glob');
const fs = require("fs-extra"); const fs = require('fs-extra');
const path = require("path"); const path = require('path');
const mkdirp = require("mkdirp"); const mkdirp = require('mkdirp');
const chalk = require("chalk"); const chalk = require('chalk');
const readMetadata = require("./server/readMetadata.js"); const readMetadata = require('./server/readMetadata.js');
const versionFallback = require("./server/versionFallback.js"); const versionFallback = require('./server/versionFallback.js');
const CWD = process.cwd(); const CWD = process.cwd();
let versions; let versions;
if (fs.existsSync(CWD + "/versions.json")) { if (fs.existsSync(CWD + '/versions.json')) {
versions = require(CWD + "/versions.json"); versions = require(CWD + '/versions.json');
} else { } else {
versions = []; versions = [];
} }
let version; let version;
const program = require("commander"); const program = require('commander');
program program
.arguments("<version>") .arguments('<version>')
.action(ver => { .action(ver => {
version = ver; version = ver;
}) })
.parse(process.argv); .parse(process.argv);
if (typeof version === "undefined") { if (typeof version === 'undefined') {
console.error( console.error(
`${chalk.yellow( `${chalk.yellow(
"No version number specified!" 'No version number specified!'
)}\nPass the version you wish to create as an argument.\nEx: 1.0.0` )}\nPass the version you wish to create as an argument.\nEx: 1.0.0`
); );
process.exit(1); process.exit(1);
@ -45,34 +45,34 @@ if (typeof version === "undefined") {
if (versions.includes(version)) { if (versions.includes(version)) {
console.error( console.error(
`${chalk.yellow( `${chalk.yellow(
"This version already exists!" 'This version already exists!'
)}\nSpecify a new version to create that does not already exist.` )}\nSpecify a new version to create that does not already exist.`
); );
process.exit(1); process.exit(1);
} }
function makeHeader(metadata) { function makeHeader(metadata) {
let header = "---\n"; let header = '---\n';
Object.keys(metadata).forEach(key => { Object.keys(metadata).forEach(key => {
header += key + ": " + metadata[key] + "\n"; header += key + ': ' + metadata[key] + '\n';
}); });
header += "---\n"; header += '---\n';
return header; return header;
} }
const versionFolder = CWD + "/versioned_docs/version-" + version; const versionFolder = CWD + '/versioned_docs/version-' + version;
mkdirp.sync(versionFolder); mkdirp.sync(versionFolder);
// copy necessary files to new version, changing some of its metadata to reflect the versioning // copy necessary files to new version, changing some of its metadata to reflect the versioning
let files = glob.sync(CWD + "/../" + readMetadata.getDocsPath() + "/*"); let files = glob.sync(CWD + '/../' + readMetadata.getDocsPath() + '/*');
files.forEach(file => { files.forEach(file => {
const ext = path.extname(file); const ext = path.extname(file);
if (ext !== ".md" && ext !== ".markdown") { if (ext !== '.md' && ext !== '.markdown') {
return; return;
} }
const res = readMetadata.extractMetadata(fs.readFileSync(file, "utf8")); const res = readMetadata.extractMetadata(fs.readFileSync(file, 'utf8'));
let metadata = res.metadata; let metadata = res.metadata;
// Don't version any docs without any metadata whatsoever. // Don't version any docs without any metadata whatsoever.
if (Object.keys(metadata).length === 0) { if (Object.keys(metadata).length === 0) {
@ -82,7 +82,7 @@ files.forEach(file => {
if (!metadata.id) { if (!metadata.id) {
metadata.id = path.basename(file, path.extname(file)); metadata.id = path.basename(file, path.extname(file));
} }
if (metadata.id.includes("/")) { if (metadata.id.includes('/')) {
throw new Error('Document id cannot include "/".'); throw new Error('Document id cannot include "/".');
} }
if (!metadata.title) { if (!metadata.title) {
@ -94,22 +94,22 @@ files.forEach(file => {
} }
metadata.original_id = metadata.id; metadata.original_id = metadata.id;
metadata.id = "version-" + version + "-" + metadata.id; metadata.id = 'version-' + version + '-' + metadata.id;
const targetFile = const targetFile =
CWD + "/versioned_docs/version-" + version + "/" + path.basename(file); CWD + '/versioned_docs/version-' + version + '/' + path.basename(file);
fs.writeFileSync(targetFile, makeHeader(metadata) + rawContent, "utf8"); fs.writeFileSync(targetFile, makeHeader(metadata) + rawContent, 'utf8');
}); });
// copy sidebar if necessary // copy sidebar if necessary
if (versionFallback.diffLatestSidebar()) { if (versionFallback.diffLatestSidebar()) {
mkdirp(CWD + "/versioned_sidebars"); mkdirp(CWD + '/versioned_sidebars');
const sidebar = JSON.parse(fs.readFileSync(CWD + "/sidebars.json", "utf8")); const sidebar = JSON.parse(fs.readFileSync(CWD + '/sidebars.json', 'utf8'));
const versioned = {}; const versioned = {};
Object.keys(sidebar).forEach(sb => { Object.keys(sidebar).forEach(sb => {
const version_sb = "version-" + version + "-" + sb; const version_sb = 'version-' + version + '-' + sb;
versioned[version_sb] = {}; versioned[version_sb] = {};
const categories = sidebar[sb]; const categories = sidebar[sb];
@ -118,20 +118,20 @@ if (versionFallback.diffLatestSidebar()) {
const ids = categories[category]; const ids = categories[category];
ids.forEach((id, index) => { ids.forEach((id, index) => {
versioned[version_sb][category].push("version-" + version + "-" + id); versioned[version_sb][category].push('version-' + version + '-' + id);
}); });
}); });
}); });
fs.writeFileSync( fs.writeFileSync(
CWD + "/versioned_sidebars/version-" + version + "-sidebars.json", CWD + '/versioned_sidebars/version-' + version + '-sidebars.json',
JSON.stringify(versioned, null, 2), JSON.stringify(versioned, null, 2),
"utf8" 'utf8'
); );
} }
// update versions.json file // update versions.json file
versions.unshift(version); versions.unshift(version);
fs.writeFileSync(CWD + "/versions.json", JSON.stringify(versions, null, 2)); fs.writeFileSync(CWD + '/versions.json', JSON.stringify(versions, null, 2));
console.log(`${chalk.green("Version " + version + " created!\n")}`); console.log(`${chalk.green('Version ' + version + ' created!\n')}`);

View file

@ -10,48 +10,48 @@
/* generate the i18n/en.json file */ /* generate the i18n/en.json file */
const CWD = process.cwd(); const CWD = process.cwd();
const fs = require("fs-extra"); const fs = require('fs-extra');
const mkdirp = require("mkdirp"); const mkdirp = require('mkdirp');
const glob = require("glob"); const glob = require('glob');
const readMetadata = require("./server/readMetadata.js"); const readMetadata = require('./server/readMetadata.js');
const path = require("path"); const path = require('path');
const siteConfig = require(CWD + "/siteConfig.js"); const siteConfig = require(CWD + '/siteConfig.js');
const babylon = require("babylon"); const babylon = require('babylon');
const traverse = require("babel-traverse").default; const traverse = require('babel-traverse').default;
const sidebars = require(CWD + "/sidebars.json"); const sidebars = require(CWD + '/sidebars.json');
let currentTranslations = { let currentTranslations = {
"localized-strings": {}, 'localized-strings': {},
"pages-strings": {} 'pages-strings': {},
}; };
if (fs.existsSync(path)) { if (fs.existsSync(path)) {
currentTranslations = JSON.parse( currentTranslations = JSON.parse(
fs.readFileSync(CWD + "/i18n/en.json", "utf8") fs.readFileSync(CWD + '/i18n/en.json', 'utf8')
); );
} }
function writeFileAndCreateFolder(file, content) { function writeFileAndCreateFolder(file, content) {
mkdirp.sync(file.replace(new RegExp("/[^/]*$"), "")); mkdirp.sync(file.replace(new RegExp('/[^/]*$'), ''));
fs.writeFileSync(file, content); fs.writeFileSync(file, content);
} }
function execute() { function execute() {
console.log("Extracting translateable strings from files..."); console.log('Extracting translateable strings from files...');
let translations = { let translations = {
"localized-strings": { 'localized-strings': {
next: "Next", next: 'Next',
previous: "Previous", previous: 'Previous',
tagline: siteConfig.tagline tagline: siteConfig.tagline,
}, },
"pages-strings": {} 'pages-strings': {},
}; };
// look through markdown headers of docs for titles and categories to translate // look through markdown headers of docs for titles and categories to translate
let files = glob.sync(CWD + "/../" + readMetadata.getDocsPath() + "/**"); let files = glob.sync(CWD + '/../' + readMetadata.getDocsPath() + '/**');
files.forEach(file => { files.forEach(file => {
const extension = path.extname(file); const extension = path.extname(file);
if (extension === ".md" || extension === ".markdown") { if (extension === '.md' || extension === '.markdown') {
let res; let res;
try { try {
res = readMetadata.processMetadata(file); res = readMetadata.processMetadata(file);
@ -64,10 +64,10 @@ function execute() {
} }
const metadata = res.metadata; const metadata = res.metadata;
translations["localized-strings"][metadata.localized_id] = metadata.title; translations['localized-strings'][metadata.localized_id] = metadata.title;
if (metadata.sidebar_label) { if (metadata.sidebar_label) {
translations["localized-strings"][metadata.sidebar_label] = translations['localized-strings'][metadata.sidebar_label] =
metadata.sidebar_label; metadata.sidebar_label;
} }
} }
@ -75,7 +75,7 @@ function execute() {
// look through header links for text to translate // look through header links for text to translate
siteConfig.headerLinks.forEach(link => { siteConfig.headerLinks.forEach(link => {
if (link.label) { if (link.label) {
translations["localized-strings"][link.label] = link.label; translations['localized-strings'][link.label] = link.label;
} }
}); });
@ -83,21 +83,25 @@ function execute() {
Object.keys(sidebars).forEach(sb => { Object.keys(sidebars).forEach(sb => {
const categories = sidebars[sb]; const categories = sidebars[sb];
Object.keys(categories).forEach(category => { Object.keys(categories).forEach(category => {
translations["localized-strings"][category] = category; translations['localized-strings'][category] = category;
}); });
}); });
files = glob.sync(CWD + "/versioned_sidebars/*"); files = glob.sync(CWD + '/versioned_sidebars/*');
files.forEach(file => { files.forEach(file => {
if (!file.endsWith("-sidebars.json")) { if (!file.endsWith('-sidebars.json')) {
if (file.endsWith("-sidebar.json")) { if (file.endsWith('-sidebar.json')) {
console.warn(`Skipping ${file}. Make sure your sidebar filenames follow this format: 'version-VERSION-sidebars.json'.`); console.warn(
`Skipping ${
file
}. Make sure your sidebar filenames follow this format: 'version-VERSION-sidebars.json'.`
);
} }
return; return;
} }
let sidebarContent; let sidebarContent;
try { try {
sidebarContent = JSON.parse(fs.readFileSync(file, "utf8")); sidebarContent = JSON.parse(fs.readFileSync(file, 'utf8'));
} catch (e) { } catch (e) {
console.error(`Could not parse ${file} into json. ${e}`); console.error(`Could not parse ${file} into json. ${e}`);
process.exit(1); process.exit(1);
@ -106,69 +110,69 @@ function execute() {
Object.keys(sidebarContent).forEach(sb => { Object.keys(sidebarContent).forEach(sb => {
const categories = sidebarContent[sb]; const categories = sidebarContent[sb];
Object.keys(categories).forEach(category => { Object.keys(categories).forEach(category => {
translations["localized-strings"][category] = category; translations['localized-strings'][category] = category;
}); });
}); });
}); });
// go through pages to look for text inside translate tags // go through pages to look for text inside translate tags
files = glob.sync(CWD + "/pages/en/**"); files = glob.sync(CWD + '/pages/en/**');
files.forEach(file => { files.forEach(file => {
const extension = path.extname(file); const extension = path.extname(file);
if (extension === ".js") { if (extension === '.js') {
const ast = babylon.parse(fs.readFileSync(file, "utf8"), { const ast = babylon.parse(fs.readFileSync(file, 'utf8'), {
plugins: ["jsx"] plugins: ['jsx'],
}); });
traverse(ast, { traverse(ast, {
enter(path) { enter(path) {
if ( if (
path.node.type === "JSXElement" && path.node.type === 'JSXElement' &&
path.node.openingElement.name.name === "translate" path.node.openingElement.name.name === 'translate'
) { ) {
const text = path.node.children[0].value const text = path.node.children[0].value
.trim() .trim()
.replace(/\s+/g, " "); .replace(/\s+/g, ' ');
let description = "no description given"; let description = 'no description given';
const attributes = path.node.openingElement.attributes; const attributes = path.node.openingElement.attributes;
for (let i = 0; i < attributes.length; i++) { for (let i = 0; i < attributes.length; i++) {
if (attributes[i].name.name === "desc") { if (attributes[i].name.name === 'desc') {
description = attributes[i].value.value; description = attributes[i].value.value;
} }
} }
translations["pages-strings"][text + "|" + description] = text; translations['pages-strings'][text + '|' + description] = text;
} }
} },
}); });
} }
}); });
// Manually add 'Help Translate' to en.json // Manually add 'Help Translate' to en.json
translations["pages-strings"][ translations['pages-strings'][
"Help Translate|recruit community translators for your project" 'Help Translate|recruit community translators for your project'
] = ] =
"Help Translate"; 'Help Translate';
translations["pages-strings"][ translations['pages-strings'][
"Edit this Doc|recruitment message asking to edit the doc source" 'Edit this Doc|recruitment message asking to edit the doc source'
] = ] =
"Edit"; 'Edit';
translations["pages-strings"][ translations['pages-strings'][
"Translate this Doc|recruitment message asking to translate the docs" 'Translate this Doc|recruitment message asking to translate the docs'
] = ] =
"Translate"; 'Translate';
translations["pages-strings"] = Object.assign( translations['pages-strings'] = Object.assign(
translations["pages-strings"], translations['pages-strings'],
currentTranslations["pages-strings"] currentTranslations['pages-strings']
); );
translations["localized-strings"] = Object.assign( translations['localized-strings'] = Object.assign(
translations["localized-strings"], translations['localized-strings'],
currentTranslations["localized-strings"] currentTranslations['localized-strings']
); );
writeFileAndCreateFolder( writeFileAndCreateFolder(
CWD + "/i18n/en.json", CWD + '/i18n/en.json',
JSON.stringify( JSON.stringify(
Object.assign( Object.assign(
{ {
_comment: "This file is auto-generated by write-translations.js" _comment: 'This file is auto-generated by write-translations.js',
}, },
translations translations
), ),

View file

@ -1,6 +1,12 @@
{ {
"scripts": { "scripts": {
"test": "true" "ci-check": "yarn prettier:diff",
"format:source": "prettier --config .prettierrc --write \"lib/**/*.js\"",
"format:examples": "prettier --config .prettierrc --write \"examples/**/*.js\"",
"nit:source": "prettier --config .prettierrc --list-different \"lib/**/*.js\"",
"nit:examples": "prettier --config .prettierrc --list-different \"examples/**/*.js\"",
"prettier": "yarn format:source && yarn format:examples",
"prettier:diff": "yarn nit:source && yarn nit:examples"
}, },
"dependencies": { "dependencies": {
"babel-preset-env": "^1.6.0", "babel-preset-env": "^1.6.0",
@ -18,7 +24,7 @@
"fs-extra": "^3.0.1", "fs-extra": "^3.0.1",
"glob": "^7.1.2", "glob": "^7.1.2",
"highlight.js": "^9.12.0", "highlight.js": "^9.12.0",
"prettier": "^1.5.3", "prettier": "1.8.2",
"react": "^15.5.4", "react": "^15.5.4",
"react-dom": "^15.5.4", "react-dom": "^15.5.4",
"react-dom-factories": "^1.0.1", "react-dom-factories": "^1.0.1",

View file

@ -1274,9 +1274,9 @@ performance-now@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
prettier@^1.5.3: prettier@1.8.2:
version "1.7.4" version "1.8.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.7.4.tgz#5e8624ae9363c80f95ec644584ecdf55d74f93fa" resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.8.2.tgz#bff83e7fd573933c607875e5ba3abbdffb96aeb8"
private@^0.1.6, private@^0.1.7: private@^0.1.6, private@^0.1.7:
version "0.1.8" version "0.1.8"