ESLintify Part 1 (#837)

* ESLint-ify

* Allow empty try/catch

* Escape regexp
This commit is contained in:
Yangshun Tay 2018-07-08 09:13:18 -07:00 committed by GitHub
parent 128dbfca0a
commit e8e3f42685
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 466 additions and 555 deletions

View file

@ -16,53 +16,23 @@ module.exports = {
'no-console': OFF, 'no-console': OFF,
// require radix argument in parseInt // require radix argument in parseInt
radix: ERROR, radix: ERROR,
'class-methods-use-this': OFF,
'react/no-multi-comp': OFF,
'import/no-extraneous-dependencies': OFF,
'react/no-danger': OFF,
'no-empty': [ERROR, {allowEmptyCatch: true}],
// Existing ESLint errors sorted by frequency, silencing first. // Existing ESLint errors sorted by frequency, silencing first.
'react/button-has-type': OFF, // 1 'react/button-has-type': OFF, // 1
null: OFF, // 1
'react/no-unused-state': OFF, // 1
'vars-on-top': OFF, // 1
'react/forbid-prop-types': OFF, // 1 'react/forbid-prop-types': OFF, // 1
'react/require-default-props': OFF, // 1 'react/require-default-props': OFF, // 1
'lines-between-class-members': OFF, // 1
strict: OFF, // 1
'no-restricted-syntax': OFF, // 1
'no-path-concat': OFF, // 2
'one-var': OFF, // 2
'no-unused-expressions': OFF, // 2
'react/jsx-boolean-value': OFF, // 2
'jsx-a11y/html-has-lang': OFF, // 2
'no-var': OFF, // 2
'no-useless-return': OFF, // 2
'jsx-a11y/anchor-has-content': OFF, // 2
'react/jsx-no-comment-textnodes': OFF, // 3
'no-continue': OFF, // 3
'jsx-a11y/alt-text': OFF, // 3
'react/jsx-tag-spacing': OFF, // 3
'no-lonely-if': OFF, // 3
'react/sort-comp': OFF, // 4
'no-cond-assign': OFF, // 4
'no-use-before-define': OFF, // 4
'no-empty': OFF, // 4
'no-shadow': OFF, // 4
'class-methods-use-this': OFF, // 5
eqeqeq: OFF, // 5
'react/no-multi-comp': OFF, // 5
'react/no-array-index-key': OFF, // 6
'no-underscore-dangle': OFF, // 6
'array-callback-return': OFF, // 6
'import/no-extraneous-dependencies': OFF, // 7
'no-else-return': OFF, // 9
'jsx-a11y/anchor-is-valid': OFF, // 9 'jsx-a11y/anchor-is-valid': OFF, // 9
'import/order': OFF, // 10
'arrow-body-style': OFF, // 10 'arrow-body-style': OFF, // 10
camelcase: OFF, // 10
'react/jsx-curly-brace-presence': OFF, // 11 'react/jsx-curly-brace-presence': OFF, // 11
'react/no-unescaped-entities': OFF, // 12 'react/no-unescaped-entities': OFF, // 12
'no-param-reassign': OFF, // 12 'no-param-reassign': OFF, // 12
'no-unused-vars': OFF, // 13
'spaced-comment': OFF, // 14 'spaced-comment': OFF, // 14
'import/no-unresolved': OFF, // 15 'import/no-unresolved': OFF, // 15
'react/no-danger': OFF, // 16
'object-shorthand': OFF, // 16 'object-shorthand': OFF, // 16
'dot-notation': OFF, // 19 'dot-notation': OFF, // 19
'react/prefer-stateless-function': OFF, // 22 'react/prefer-stateless-function': OFF, // 22

View file

@ -72,7 +72,7 @@ class Footer extends React.Component {
href={this.props.config.repoUrl} href={this.props.config.repoUrl}
data-icon="octicon-star" data-icon="octicon-star"
data-count-href="/facebook/docusaurus/stargazers" data-count-href="/facebook/docusaurus/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

View file

@ -52,11 +52,11 @@ const SplashContainer = props => (
const Logo = props => ( const Logo = props => (
<div className="projectLogo"> <div className="projectLogo">
<img src={props.img_src} /> <img src={props.img_src} alt="Project Logo" />
</div> </div>
); );
const ProjectTitle = props => ( const ProjectTitle = () => (
<h2 className="projectTitle"> <h2 className="projectTitle">
{siteConfig.title} {siteConfig.title}
<small>{siteConfig.tagline}</small> <small>{siteConfig.tagline}</small>
@ -99,7 +99,7 @@ const Block = props => (
</Container> </Container>
); );
const Features = props => ( const Features = () => (
<Block layout="fourColumn"> <Block layout="fourColumn">
{[ {[
{ {
@ -118,7 +118,7 @@ const Features = props => (
</Block> </Block>
); );
const FeatureCallout = props => ( const FeatureCallout = () => (
<div <div
className="productShowcaseSection paddingBottom" className="productShowcaseSection paddingBottom"
style={{textAlign: 'center'}}> style={{textAlign: 'center'}}>
@ -127,7 +127,7 @@ const FeatureCallout = props => (
</div> </div>
); );
const LearnHow = props => ( const LearnHow = () => (
<Block background="light"> <Block background="light">
{[ {[
{ {
@ -140,7 +140,7 @@ const LearnHow = props => (
</Block> </Block>
); );
const TryOut = props => ( const TryOut = () => (
<Block id="try"> <Block id="try">
{[ {[
{ {
@ -153,7 +153,7 @@ const TryOut = props => (
</Block> </Block>
); );
const Description = props => ( const Description = () => (
<Block background="dark"> <Block background="dark">
{[ {[
{ {
@ -170,21 +170,16 @@ const Showcase = props => {
if ((siteConfig.users || []).length === 0) { if ((siteConfig.users || []).length === 0) {
return null; return null;
} }
const showcase = siteConfig.users
.filter(user => { const showcase = siteConfig.users.filter(user => user.pinned).map(user => (
return user.pinned; <a href={user.infoLink} key={user.infoLink}>
})
.map((user, i) => {
return (
<a href={user.infoLink} key={i}>
<img src={user.image} alt={user.caption} title={user.caption} /> <img src={user.image} alt={user.caption} title={user.caption} />
</a> </a>
); ));
});
return ( return (
<div className="productShowcaseSection paddingBottom"> <div className="productShowcaseSection paddingBottom">
<h2>{"Who's Using This?"}</h2> <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">{showcase}</div> <div className="logos">{showcase}</div>
<div className="more-users"> <div className="more-users">

View file

@ -17,14 +17,13 @@ class Users extends React.Component {
if ((siteConfig.users || []).length === 0) { if ((siteConfig.users || []).length === 0) {
return null; return null;
} }
const editUrl = siteConfig.repoUrl + '/edit/master/website/siteConfig.js'; const editUrl = siteConfig.repoUrl + '/edit/master/website/siteConfig.js';
const showcase = siteConfig.users.map((user, i) => { const showcase = siteConfig.users.map(user => (
return ( <a href={user.infoLink} key={user.infoLink}>
<a href={user.infoLink} key={i}>
<img src={user.image} alt={user.caption} title={user.caption} /> <img src={user.image} alt={user.caption} title={user.caption} />
</a> </a>
); ));
});
return ( return (
<div className="mainContainer"> <div className="mainContainer">

View file

@ -52,7 +52,6 @@ beforeAll(() => {
inputAssetsFiles, inputAssetsFiles,
outputAssetsFiles, outputAssetsFiles,
] = results; ] = results;
return;
}); });
}); });

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 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 Site = require('./Site.js'); const Site = require('./Site.js');
const utils = require('./utils.js'); const utils = require('./utils.js');
@ -46,7 +46,7 @@ class BlogPageLayout extends React.Component {
<BlogPost <BlogPost
post={post} post={post}
content={post.content} content={post.content}
truncate={true} truncate
key={ key={
utils.getPath(post.path, this.props.config.cleanUrl) + utils.getPath(post.path, this.props.config.cleanUrl) +
post.title post.title

View file

@ -5,9 +5,9 @@
* 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 React = require('react'); const React = require('react');
const MarkdownBlock = require('./MarkdownBlock.js');
const utils = require('./utils.js'); const utils = require('./utils.js');
// inner blog component for the article itself, without sidebar/header/footer // inner blog component for the article itself, without sidebar/header/footer
@ -46,33 +46,22 @@ class BlogPost extends React.Component {
const className = const className =
'authorPhoto' + 'authorPhoto' +
(post.author && post.authorTitle ? ' authorPhotoBig' : ''); (post.author && post.authorTitle ? ' authorPhotoBig' : '');
if (post.authorFBID) { if (post.authorFBID || post.authorImageURL) {
const authorImageURL = post.authorFBID
? `https://graph.facebook.com/${
post.authorFBID
}/picture/?height=200&width=200`
: post.authorImageURL;
return ( return (
<div className={className}> <div className={className}>
<a href={post.authorURL} target="_blank" rel="noreferrer noopener"> <a href={post.authorURL} target="_blank" rel="noreferrer noopener">
<img <img src={authorImageURL} alt={post.author} />
src={ </a>
'https://graph.facebook.com/' + </div>
post.authorFBID + );
'/picture/?height=200&width=200'
} }
alt={post.author}
/>
</a>
</div>
);
} else if (post.authorImageURL) {
return (
<div className={className}>
<a href={post.authorURL} target="_blank" rel="noreferrer noopener">
<img src={post.authorImageURL} />
</a>
</div>
);
} else {
return null; return null;
} }
}
renderTitle() { renderTitle() {
const post = this.props.post; const post = this.props.post;

View file

@ -5,19 +5,31 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const classNames = require('classnames');
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');
const OnPageNav = require('./nav/OnPageNav.js'); const OnPageNav = require('./nav/OnPageNav.js');
const utils = require('./utils.js'); const utils = require('./utils.js');
const classNames = require('classnames');
// 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 {
getDescription() {
const descLines = this.props.children.trim().split('\n');
for (let i = 0; i < descLines.length; i++) {
// Don't want blank lines or descriptions that are raw image rendering strings.
if (descLines[i] && !descLines[i].startsWith('![')) {
return descLines[i];
}
}
return null;
}
renderSocialButtons() { renderSocialButtons() {
let post = this.props.metadata; const post = this.props.metadata;
post.path = utils.getPath(post.path, this.props.config.cleanUrl); post.path = utils.getPath(post.path, this.props.config.cleanUrl);
const fbComment = this.props.config.facebookAppId && const fbComment = this.props.config.facebookAppId &&
@ -72,8 +84,9 @@ class BlogPostLayout extends React.Component {
} }
data-related={this.props.config.twitter} data-related={this.props.config.twitter}
data-via={post.authorTwitter} data-via={post.authorTwitter}
data-show-count="false" data-show-count="false">
/> Tweet
</a>
</div> </div>
); );
@ -86,17 +99,6 @@ class BlogPostLayout extends React.Component {
); );
} }
getDescription() {
const descLines = this.props.children.trim().split('\n');
for (var i = 0; i < descLines.length; i++) {
// Don't want blank lines or descriptions that are raw image rendering strings
if (descLines[i] && !descLines[i].startsWith('![')) {
return descLines[i];
}
}
return null;
}
render() { render() {
const hasOnPageNav = this.props.config.onPageNav === 'separate'; const hasOnPageNav = this.props.config.onPageNav === 'separate';
const post = this.props.metadata; const post = this.props.metadata;

View file

@ -17,7 +17,7 @@ class BlogSidebar extends React.Component {
let blogSidebarTitleConfig = this.props.config.blogSidebarTitle || {}; let blogSidebarTitleConfig = this.props.config.blogSidebarTitle || {};
let blogSidebarTitle = blogSidebarTitleConfig.default || 'Recent Posts'; let blogSidebarTitle = blogSidebarTitleConfig.default || 'Recent Posts';
if (this.props.config.blogSidebarCount) { if (this.props.config.blogSidebarCount) {
if (this.props.config.blogSidebarCount == 'ALL') { if (this.props.config.blogSidebarCount === 'ALL') {
blogSidebarCount = MetadataBlog.length; blogSidebarCount = MetadataBlog.length;
blogSidebarTitle = blogSidebarTitleConfig.all || 'All Blog Posts'; blogSidebarTitle = blogSidebarTitleConfig.all || 'All Blog Posts';
} else { } else {

View file

@ -43,7 +43,7 @@ class Doc extends React.Component {
// If internationalization is enabled, show Recruiting link instead of Edit Link. // If internationalization is enabled, show Recruiting link instead of Edit Link.
if ( if (
this.props.language && this.props.language &&
this.props.language != 'en' && this.props.language !== 'en' &&
this.props.config.translationRecruitingLink this.props.config.translationRecruitingLink
) { ) {
editLink = ( editLink = (

View file

@ -5,16 +5,17 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const classNames = require('classnames');
const path = require('path');
const React = require('react'); const React = require('react');
const url = require('url');
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 OnPageNav = require('./nav/OnPageNav.js'); const OnPageNav = require('./nav/OnPageNav.js');
const Site = require('./Site.js'); const Site = require('./Site.js');
const translation = require('../server/translation.js'); const translation = require('../server/translation.js');
const classNames = require('classnames');
const path = require('path');
const url = require('url');
// 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 {

View file

@ -48,37 +48,33 @@ class GridBlock extends React.Component {
} }
renderBlockImage(image, imageLink, imageAlt) { renderBlockImage(image, imageLink, imageAlt) {
if (image) { if (!image) {
if (imageLink) { return null;
}
return ( return (
<div className="blockImage"> <div className="blockImage">
{imageLink ? (
<a href={imageLink}> <a href={imageLink}>
<img src={image} alt={imageAlt} /> <img src={image} alt={imageAlt} />
</a> </a>
</div> ) : (
);
} else {
return (
<div className="blockImage">
<img src={image} alt={imageAlt} /> <img src={image} alt={imageAlt} />
)}
</div> </div>
); );
} }
} else {
return null;
}
}
renderBlockTitle(title) { renderBlockTitle(title) {
if (title) { if (!title) {
return null;
}
return ( return (
<h2> <h2>
<MarkdownBlock>{title}</MarkdownBlock> <MarkdownBlock>{title}</MarkdownBlock>
</h2> </h2>
); );
} else {
return null;
}
} }
render() { render() {

View file

@ -11,10 +11,7 @@ const React = require('react');
class Head extends React.Component { class Head extends React.Component {
render() { render() {
const links = this.props.config.headerLinks; const links = this.props.config.headerLinks;
let hasBlog = false; const hasBlog = links.some(link => link.blog);
links.map(link => {
if (link.blog) hasBlog = true;
});
let highlight = { let highlight = {
version: '9.12.0', version: '9.12.0',
@ -137,21 +134,13 @@ class Head extends React.Component {
{/* External resources */} {/* External resources */}
{this.props.config.stylesheets && {this.props.config.stylesheets &&
this.props.config.stylesheets.map(function(source, idx) { this.props.config.stylesheets.map(source => (
return ( <link rel="stylesheet" key={source} href={source} />
<link rel="stylesheet" key={'stylesheet' + idx} href={source} /> ))}
);
})}
{this.props.config.scripts && {this.props.config.scripts &&
this.props.config.scripts.map(function(source, idx) { this.props.config.scripts.map(source => (
return ( <script type="text/javascript" key={source} src={source} />
<script ))}
type="text/javascript"
key={'script' + idx}
src={source}
/>
);
})}
{this.props.config.scrollToTop && ( {this.props.config.scrollToTop && (
<script <script

View file

@ -1,28 +0,0 @@
/**
* Copyright (c) 2017-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const React = require('react');
const toSlug = require('./toSlug.js');
class Header extends React.Component {
render() {
const slug = toSlug(this.props.toSlug || this.props.children);
const Heading = 'h' + this.props.level;
return (
<Heading {...this.props}>
<a className="anchor" id={slug} />
{this.props.children}{' '}
<a className="hash-link" href={'#' + slug}>
#
</a>
</Heading>
);
}
}
module.exports = Header;

View file

@ -29,7 +29,7 @@ class Redirect extends React.Component {
const redirect = this.props.redirect || false; const redirect = this.props.redirect || false;
return ( return (
<html> <html lang="en">
<Head <Head
config={this.props.config} config={this.props.config}
description={description} description={description}

View file

@ -5,8 +5,6 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
'use strict';
const React = require('react'); const React = require('react');
const renderMarkdown = require('./renderMarkdown.js'); const renderMarkdown = require('./renderMarkdown.js');
@ -20,22 +18,21 @@ class Remarkable extends React.Component {
}} }}
/> />
); );
} 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 ( return (
<span dangerouslySetInnerHTML={{__html: renderMarkdown(child)}} /> <span dangerouslySetInnerHTML={{__html: renderMarkdown(child)}} />
); );
} else { }
return child; return child;
}
}); });
} }
}
render() { render() {
var Container = this.props.container; const Container = this.props.container;
return <Container>{this.content()}</Container>; return <Container>{this.content()}</Container>;
} }
} }

View file

@ -39,14 +39,8 @@ class Site extends React.Component {
docsVersion = latestVersion; docsVersion = latestVersion;
} }
// We do not want a lang attribute for the html tag if we don't have a language set
const htmlElementProps = {};
if (this.props.language) {
htmlElementProps.lang = this.props.language;
}
return ( return (
<html {...htmlElementProps}> <html lang={this.props.language}>
<Head <Head
config={this.props.config} config={this.props.config}
description={description} description={description}

View file

@ -5,8 +5,8 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const anchors = require('../anchors');
const rules = require('remarkable/lib/rules'); const rules = require('remarkable/lib/rules');
const anchors = require('../anchors');
const md = { const md = {
renderer: { renderer: {

View file

@ -11,7 +11,7 @@ const getTOC = require('../getTOC');
const mdContents = readFileSync( const mdContents = readFileSync(
path.join(__dirname, '__fixtures__', 'getTOC.md'), path.join(__dirname, '__fixtures__', 'getTOC.md'),
'utf-8' 'utf8'
); );
test('with defaults', () => { test('with defaults', () => {

View file

@ -6,17 +6,17 @@
*/ */
const path = require('path'); const path = require('path');
const fs = require('fs');
const utils = require('../utils'); const utils = require('../utils');
const readFileSync = require('fs').readFileSync;
const blogPostWithTruncateContents = readFileSync( const blogPostWithTruncateContents = fs.readFileSync(
path.join(__dirname, '__fixtures__', 'blog-post-with-truncate.md'), path.join(__dirname, '__fixtures__', 'blog-post-with-truncate.md'),
'utf-8' 'utf8'
); );
const blogPostWithoutTruncateContents = readFileSync( const blogPostWithoutTruncateContents = fs.readFileSync(
path.join(__dirname, '__fixtures__', 'blog-post-without-truncate.md'), path.join(__dirname, '__fixtures__', 'blog-post-without-truncate.md'),
'utf-8' 'utf8'
); );
describe('utils', () => { describe('utils', () => {

View file

@ -52,8 +52,8 @@ module.exports = (content, headingTags = 'h2', subHeadingTags = 'h3') => {
if (headingLevels.includes(heading.lvl)) { if (headingLevels.includes(heading.lvl)) {
toc.push(entry); toc.push(entry);
current = entry; current = entry;
} else { } else if (current) {
current && current.children.push(entry); current.children.push(entry);
} }
}); });

View file

@ -89,6 +89,7 @@ class LanguageDropDown extends React.Component {
<img <img
className="languages-icon" className="languages-icon"
src={this.props.baseUrl + 'img/language.svg'} src={this.props.baseUrl + 'img/language.svg'}
alt="Languages icon"
/> />
{currentLanguage} {currentLanguage}
</a> </a>
@ -120,12 +121,6 @@ class LanguageDropDown extends React.Component {
// header navbar used by all pages generated with docusaurus // header navbar used by all pages generated with docusaurus
class HeaderNav extends React.Component { class HeaderNav extends React.Component {
constructor() {
super();
this.state = {
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
makeLinks(link) { makeLinks(link) {
let href; let href;
@ -143,7 +138,8 @@ class HeaderNav extends React.Component {
/> />
</li> </li>
); );
} else if (link.languages) { }
if (link.languages) {
if ( if (
env.translation.enabled && env.translation.enabled &&
env.translation.enabledLanguages().length > 1 env.translation.enabledLanguages().length > 1
@ -157,10 +153,10 @@ class HeaderNav extends React.Component {
key="languagedropdown" key="languagedropdown"
/> />
); );
} else { }
return null; return null;
} }
} else if (link.doc) { if (link.doc) {
// set link to document with current page's language/version // set link to document with current page's language/version
const langPart = env.translation.enabled const langPart = env.translation.enabled
? (this.props.language || 'en') + '-' ? (this.props.language || 'en') + '-'
@ -238,47 +234,6 @@ class HeaderNav extends React.Component {
); );
} }
render() {
const headerClass = siteConfig.headerIcon
? 'headerTitleWithLogo'
: 'headerTitle';
const versionsLink =
this.props.baseUrl +
(env.translation.enabled
? this.props.language + '/versions' + extension
: 'versions' + extension);
return (
<div className="fixedHeaderContainer">
<div className="headerWrapper wrapper">
<header>
<a
href={
this.props.baseUrl +
(env.translation.enabled ? this.props.language : '')
}>
{siteConfig.headerIcon && (
<img
className="logo"
src={this.props.baseUrl + siteConfig.headerIcon}
alt={siteConfig.title}
/>
)}
{!this.props.config.disableHeaderTitle && (
<h2 className={headerClass}>{this.props.title}</h2>
)}
</a>
{env.versioning.enabled && (
<a href={versionsLink}>
<h3>{this.props.version || env.versioning.defaultVersion}</h3>
</a>
)}
{this.renderResponsiveNav()}
</header>
</div>
</div>
);
}
renderResponsiveNav() { renderResponsiveNav() {
const headerLinks = this.props.config.headerLinks; const headerLinks = this.props.config.headerLinks;
// add language drop down to end if location not specified // add language drop down to end if location not specified
@ -336,6 +291,47 @@ class HeaderNav extends React.Component {
</div> </div>
); );
} }
render() {
const headerClass = siteConfig.headerIcon
? 'headerTitleWithLogo'
: 'headerTitle';
const versionsLink =
this.props.baseUrl +
(env.translation.enabled
? this.props.language + '/versions' + extension
: 'versions' + extension);
return (
<div className="fixedHeaderContainer">
<div className="headerWrapper wrapper">
<header>
<a
href={
this.props.baseUrl +
(env.translation.enabled ? this.props.language : '')
}>
{siteConfig.headerIcon && (
<img
className="logo"
src={this.props.baseUrl + siteConfig.headerIcon}
alt={siteConfig.title}
/>
)}
{!this.props.config.disableHeaderTitle && (
<h2 className={headerClass}>{this.props.title}</h2>
)}
</a>
{env.versioning.enabled && (
<a href={versionsLink}>
<h3>{this.props.version || env.versioning.defaultVersion}</h3>
</a>
)}
{this.renderResponsiveNav()}
</header>
</div>
</div>
);
}
} }
HeaderNav.defaultProps = { HeaderNav.defaultProps = {

View file

@ -23,8 +23,8 @@ const Headings = ({headings}) => {
if (!headings.length) return null; if (!headings.length) return null;
return ( return (
<ul className="toc-headings"> <ul className="toc-headings">
{headings.map((heading, i) => ( {headings.map(heading => (
<li key={i}> <li key={heading.hashLink}>
<Link hashLink={heading.hashLink} content={heading.content} /> <Link hashLink={heading.hashLink} content={heading.content} />
<Headings headings={heading.children} /> <Headings headings={heading.children} />
</li> </li>

View file

@ -13,6 +13,77 @@ const translation = require('../../server/translation.js');
const utils = require('../utils.js'); const utils = require('../utils.js');
class SideNav extends React.Component { class SideNav extends React.Component {
// return appropriately translated category string
getLocalizedCategoryString(category) {
let categoryString = translation[this.props.language]
? translation[this.props.language]['localized-strings'][category] ||
category
: category;
return categoryString;
}
// return appropriately translated label to use for doc/blog in sidebar
getLocalizedString(metadata) {
let localizedString;
const i18n = translation[this.props.language];
const sbTitle = metadata.sidebar_label;
if (sbTitle) {
localizedString = i18n
? i18n['localized-strings'][sbTitle] || sbTitle
: sbTitle;
} else {
const id = metadata.original_id || metadata.localized_id;
localizedString = i18n
? i18n['localized-strings'][id] || metadata.title
: metadata.title;
}
return localizedString;
}
// return link to doc in sidebar
getLink(metadata) {
if (metadata.permalink) {
const targetLink = utils.getPath(metadata.permalink, siteConfig.cleanUrl);
if (targetLink.match(/^https?:/)) {
return targetLink;
}
return siteConfig.baseUrl + targetLink;
}
if (metadata.path) {
return (
siteConfig.baseUrl +
'blog/' +
utils.getPath(metadata.path, siteConfig.cleanUrl)
);
}
return null;
}
renderCategory(category) {
return (
<div className="navGroup" key={category.name}>
<h3 className="navGroupCategoryTitle">
{this.getLocalizedCategoryString(category.name)}
</h3>
<ul>{category.links.map(this.renderItemLink, this)}</ul>
</div>
);
}
renderItemLink(link) {
const itemClasses = classNames('navListItem', {
navListItemActive: link.id === this.props.current.id,
});
return (
<li className={itemClasses} key={link.id}>
<a className="navItem" href={this.getLink(link)}>
{this.getLocalizedString(link)}
</a>
</li>
);
}
render() { render() {
return ( return (
<nav className="toc"> <nav className="toc">
@ -70,77 +141,6 @@ class SideNav extends React.Component {
</nav> </nav>
); );
} }
renderCategory(category) {
return (
<div className="navGroup" key={category.name}>
<h3 className="navGroupCategoryTitle">
{this.getLocalizedCategoryString(category.name)}
</h3>
<ul>{category.links.map(this.renderItemLink, this)}</ul>
</div>
);
}
// return appropriately translated category string
getLocalizedCategoryString(category) {
let categoryString = translation[this.props.language]
? translation[this.props.language]['localized-strings'][category] ||
category
: category;
return categoryString;
}
// return appropriately translated label to use for doc/blog in sidebar
getLocalizedString(metadata) {
let localizedString;
const i18n = translation[this.props.language];
const sbTitle = metadata.sidebar_label;
if (sbTitle) {
localizedString = i18n
? i18n['localized-strings'][sbTitle] || sbTitle
: sbTitle;
} else {
const id = metadata.original_id || metadata.localized_id;
localizedString = i18n
? i18n['localized-strings'][id] || metadata.title
: metadata.title;
}
return localizedString;
}
// return link to doc in sidebar
getLink(metadata) {
if (metadata.permalink) {
const targetLink = utils.getPath(metadata.permalink, siteConfig.cleanUrl);
if (targetLink.match(/^https?:/)) {
return targetLink;
}
return siteConfig.baseUrl + targetLink;
}
if (metadata.path) {
return (
siteConfig.baseUrl +
'blog/' +
utils.getPath(metadata.path, siteConfig.cleanUrl)
);
}
return null;
}
renderItemLink(link) {
const itemClasses = classNames('navListItem', {
navListItemActive: link.id === this.props.current.id,
});
return (
<li className={itemClasses} key={link.id}>
<a className="navItem" href={this.getLink(link)}>
{this.getLocalizedString(link)}
</a>
</li>
);
}
} }
SideNav.defaultProps = { SideNav.defaultProps = {

View file

@ -42,17 +42,23 @@ class MarkdownRenderer {
// every single language (https://github.com/PrismJS/prism/issues/593) // every single language (https://github.com/PrismJS/prism/issues/593)
require('prismjs/components/prism-' + language + '.min'); require('prismjs/components/prism-' + language + '.min');
return prismjs.highlight(str, prismjs.languages[language]); return prismjs.highlight(str, prismjs.languages[language]);
} catch (err) {} } catch (err) {
console.error(err);
}
} }
if (hljs.getLanguage(lang)) { if (hljs.getLanguage(lang)) {
return hljs.highlight(lang, str).value; return hljs.highlight(lang, str).value;
} }
} catch (err) {} } catch (err) {
console.error(err);
}
} }
try { try {
return hljs.highlightAuto(str).value; return hljs.highlightAuto(str).value;
} catch (err) {} } catch (err) {
console.error(err);
}
return ''; return '';
}, },
@ -70,11 +76,11 @@ class MarkdownRenderer {
}); });
} }
this._md = md; this.md = md;
} }
toHtml(source) { toHtml(source) {
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

View file

@ -26,12 +26,11 @@ function removeExtension(path) {
function getPath(path, cleanUrl = false) { function getPath(path, cleanUrl = false) {
if (cleanUrl) { if (cleanUrl) {
if (path.endsWith('/index.html')) { return path.endsWith('/index.html')
return path.replace(/\/index.html$/, ''); ? path.replace(/\/index.html$/, '')
} else { : removeExtension(path);
return removeExtension(path);
}
} }
return path; return path;
} }

View file

@ -111,8 +111,7 @@ if (defaultBranch !== DEPLOYMENT_BRANCH) {
shell.echo(`Error: Git checkout ${DEPLOYMENT_BRANCH} failed`); shell.echo(`Error: Git checkout ${DEPLOYMENT_BRANCH} failed`);
shell.exit(1); shell.exit(1);
} }
} 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}`) shell.exec(`git branch --set-upstream-to=origin/${DEPLOYMENT_BRANCH}`)
.code !== .code !==
@ -122,7 +121,6 @@ if (defaultBranch !== DEPLOYMENT_BRANCH) {
shell.exit(1); shell.exit(1);
} }
} }
}
shell.exec('git rm -rf .'); shell.exec('git rm -rf .');
@ -140,7 +138,7 @@ const excludePath = `${PROJECT_NAME}-${DEPLOYMENT_BRANCH}`;
fs.copy( fs.copy(
fromPath, fromPath,
toPath, toPath,
(src, dest) => { src => {
if (src.indexOf('.DS_Store') !== -1) { if (src.indexOf('.DS_Store') !== -1) {
return false; return false;
} }

View file

@ -8,18 +8,16 @@
*/ */
const chalk = require('chalk'); const chalk = require('chalk');
const program = require('commander');
const escapeStringRegexp = require('escape-string-regexp');
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 metadataUtils = require('./server/metadataUtils.js'); const metadataUtils = require('./server/metadataUtils.js');
const CWD = process.cwd(); const CWD = process.cwd();
// escape appropriate characters in a string to be used in a regex
RegExp.escape = function(s) {
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';
@ -30,9 +28,8 @@ function makeHeader(metadata) {
return header; return header;
} }
let currentVersion, newVersion; let currentVersion;
let newVersion;
const program = require('commander');
program program
.arguments('<version_name> <new_version_name>') .arguments('<version_name> <new_version_name>')
@ -123,7 +120,7 @@ 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-${escapeStringRegexp(currentVersion)}-`, 'g'),
`version-${newVersion}-` `version-${newVersion}-`
); );
fs.writeFileSync(newSidebarFile, sidebarContent); fs.writeFileSync(newSidebarFile, sidebarContent);

View file

@ -13,9 +13,9 @@ const siteConfig = require(CWD + '/siteConfig.js');
const join = path.join; const join = path.join;
const languages_js = join(CWD, 'languages.js'); const languagesFile = join(CWD, 'languages.js');
const versions_json = join(CWD, 'versions.json'); const versionsJSONFile = join(CWD, 'versions.json');
const versions_js = join(CWD, 'pages/en/versions.js'); const versionsFile = join(CWD, 'pages/en/versions.js');
class Translation { class Translation {
constructor() { constructor() {
@ -28,17 +28,15 @@ class Translation {
}, },
]; ];
this._load(); this.load();
} }
enabledLanguages() { enabledLanguages = () => this.languages.filter(lang => lang.enabled);
return this.languages.filter(lang => lang.enabled);
}
_load() { load() {
if (fs.existsSync(languages_js)) { if (fs.existsSync(languagesFile)) {
this.enabled = true; this.enabled = true;
this.languages = require(languages_js); this.languages = require(languagesFile);
} }
} }
} }
@ -50,7 +48,7 @@ class Versioning {
this.versions = []; this.versions = [];
this.missingVersionsPage = false; this.missingVersionsPage = false;
this._load(); this.load();
} }
printMissingVersionsPageError() { printMissingVersionsPageError() {
@ -61,16 +59,16 @@ class Versioning {
); );
} }
_load() { load() {
if (fs.existsSync(versions_json)) { if (fs.existsSync(versionsJSONFile)) {
this.enabled = true; this.enabled = true;
this.versions = JSON.parse(fs.readFileSync(versions_json, 'utf8')); this.versions = JSON.parse(fs.readFileSync(versionsJSONFile, 'utf8'));
this.defaultVersion = siteConfig.defaultVersionShown this.defaultVersion = siteConfig.defaultVersionShown
? siteConfig.defaultVersionShown ? siteConfig.defaultVersionShown
: this.versions[0]; // otherwise show the latest version (other than next/master) : this.versions[0]; // otherwise show the latest version (other than next/master)
} }
if (!fs.existsSync(versions_js)) { if (!fs.existsSync(versionsFile)) {
this.missingVersionsPage = true; this.missingVersionsPage = true;
} }
} }

View file

@ -137,13 +137,11 @@ async function execute() {
} 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);
} }
}
if (!fs.existsSync(file)) { if (!fs.existsSync(file)) {
return; return;
@ -156,14 +154,14 @@ async function execute() {
const language = metadata.language; const language = metadata.language;
// generate table of contents if appropriate // generate table of contents if appropriate
if (rawContent && rawContent.indexOf(TABLE_OF_CONTENTS_TOKEN) != -1) { if (rawContent && rawContent.indexOf(TABLE_OF_CONTENTS_TOKEN) !== -1) {
rawContent = insertTableOfContents(rawContent); rawContent = insertTableOfContents(rawContent);
} }
let defaultVersion = env.versioning.defaultVersion; let defaultVersion = env.versioning.defaultVersion;
// replace any links to markdown files to their website html links // replace any links to markdown files to their website html links
Object.keys(mdToHtml).forEach(function(key, index) { Object.keys(mdToHtml).forEach(key => {
let link = mdToHtml[key]; let link = mdToHtml[key];
link = utils.getPath(link, siteConfig.cleanUrl); link = utils.getPath(link, siteConfig.cleanUrl);
link = link.replace('/en/', '/' + language + '/'); link = link.replace('/en/', '/' + language + '/');
@ -489,18 +487,16 @@ async function execute() {
const match = regexLang.exec(normalizedFile); const match = regexLang.exec(normalizedFile);
const langParts = match[1].split(sep); const langParts = match[1].split(sep);
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]; const 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' ||
fs.existsSync( !fs.existsSync(
normalizedFile.replace(sep + 'en' + sep, sep + language + sep) normalizedFile.replace(sep + 'en' + sep, sep + language + sep)
) )
) { ) {
continue;
}
translate.setLanguage(language); translate.setLanguage(language);
const str = renderToStaticMarkupWithDoctype( const str = renderToStaticMarkupWithDoctype(
<Site <Site
@ -518,6 +514,7 @@ async function execute() {
str str
); );
} }
}
// write to base level // write to base level
let language = env.translation.enabled ? 'en' : ''; let language = env.translation.enabled ? 'en' : '';

View file

@ -55,7 +55,9 @@ function extractMetadata(content) {
.trim(); .trim();
try { try {
value = JSON.parse(value); value = JSON.parse(value);
} catch (e) {} } catch (err) {
// Ignore the error as it means it's not a JSON value.
}
metadata[key] = value; metadata[key] = value;
} }
return {metadata, rawContent: both.content}; return {metadata, rawContent: both.content};

View file

@ -5,10 +5,11 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const CWD = process.cwd(); const fs = require('fs');
const Metadata = require('../core/metadata.js'); const Metadata = require('../core/metadata.js');
const fs = require('fs');
const CWD = process.cwd();
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');
@ -24,10 +25,9 @@ if (fs.existsSync(CWD + '/languages.js')) {
// returns data broken up into categories for a sidebar // returns data broken up into categories for a sidebar
function readCategories(sidebar) { function readCategories(sidebar) {
const enabledLanguages = []; const enabledLanguages = languages
languages.filter(lang => lang.enabled).map(lang => { .filter(lang => lang.enabled)
enabledLanguages.push(lang.tag); .map(lang => lang.tag);
});
const allCategories = {}; const allCategories = {};
@ -88,7 +88,9 @@ function readCategories(sidebar) {
let i = 0; let i = 0;
while (metadata && i++ < 1000) { while (metadata && i++ < 1000) {
if (!currentCategory || metadata.category !== currentCategory.name) { if (!currentCategory || metadata.category !== currentCategory.name) {
currentCategory && categories.push(currentCategory); if (currentCategory) {
categories.push(currentCategory);
}
currentCategory = { currentCategory = {
name: metadata.category, name: metadata.category,
links: [], links: [],

View file

@ -66,7 +66,8 @@ function readSidebar() {
for (let i = 0; i < ids.length; i++) { for (let i = 0; i < ids.length; i++) {
const id = ids[i]; const id = ids[i];
let previous, next; let previous;
let next;
if (i > 0) previous = ids[i - 1]; if (i > 0) previous = ids[i - 1];
if (i < ids.length - 1) next = ids[i + 1]; if (i < ids.length - 1) next = ids[i + 1];
order[id] = { order[id] = {
@ -86,13 +87,13 @@ function processMetadata(file, refDir) {
const language = utils.getLanguage(file, refDir) || 'en'; const language = utils.getLanguage(file, refDir) || 'en';
const metadata = {}; const metadata = {};
for (const fieldName of Object.keys(result.metadata)) { Object.keys(result.metadata).forEach(fieldName => {
if (SupportedHeaderFields.has(fieldName)) { if (SupportedHeaderFields.has(fieldName)) {
metadata[fieldName] = result.metadata[fieldName]; metadata[fieldName] = result.metadata[fieldName];
} else { } else {
console.warn(`Header field "${fieldName}" in ${file} is not supported.`); console.warn(`Header field "${fieldName}" in ${file} is not supported.`);
} }
} });
const rawContent = result.rawContent; const rawContent = result.rawContent;
@ -193,10 +194,8 @@ function generateMetadataDocs() {
// create a default list of documents for each enabled language based on docs in English // create a default list of documents for each enabled language based on docs in English
// 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 => currentLanguage !== 'en')
return currentLanguage != 'en'; .forEach(currentLanguage => {
})
.map(currentLanguage => {
let baseMetadata = Object.assign({}, metadata); let baseMetadata = Object.assign({}, metadata);
baseMetadata['id'] = baseMetadata['id'] baseMetadata['id'] = baseMetadata['id']
.toString() .toString()
@ -291,7 +290,7 @@ function generateMetadataDocs() {
}); });
fs.writeFileSync( fs.writeFileSync(
__dirname + '/../core/metadata.js', path.join(__dirname, '/../core/metadata.js'),
'/**\n' + '/**\n' +
' * @' + ' * @' +
'generated\n' + // separate this out for Nuclide treating @generated as readonly 'generated\n' + // separate this out for Nuclide treating @generated as readonly
@ -360,7 +359,7 @@ function generateMetadataBlog() {
); );
fs.writeFileSync( fs.writeFileSync(
__dirname + '/../core/MetadataBlog.js', path.join(__dirname, '/../core/MetadataBlog.js'),
'/**\n' + '/**\n' +
' * @' + ' * @' +
'generated\n' + // separate this out for Nuclide treating @generated as readonly 'generated\n' + // separate this out for Nuclide treating @generated as readonly

View file

@ -5,6 +5,8 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
/* eslint-disable no-cond-assign */
function execute(port, options) { function execute(port, options) {
const extractTranslations = require('../write-translations'); const extractTranslations = require('../write-translations');
@ -45,8 +47,18 @@ function execute(port, options) {
const join = path.join; const join = path.join;
const sep = path.sep; const sep = path.sep;
// remove a module and child modules from require cache, so server does not have function removeModulePathFromCache(moduleName) {
// to be restarted /* eslint-disable no-underscore-dangle */
Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
if (cacheKey.indexOf(moduleName) > 0) {
delete module.constructor._pathCache[cacheKey];
}
});
/* eslint-enable no-underscore-dangle */
}
// Remove a module and child modules from require cache, so server
// does not have to be restarted.
function removeModuleAndChildrenFromCache(moduleName) { function removeModuleAndChildrenFromCache(moduleName) {
let mod = require.resolve(moduleName); let mod = require.resolve(moduleName);
if (mod && (mod = require.cache[mod])) { if (mod && (mod = require.cache[mod])) {
@ -59,14 +71,6 @@ function execute(port, options) {
} }
} }
function removeModulePathFromCache(moduleName) {
Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
if (cacheKey.indexOf(moduleName) > 0) {
delete module.constructor._pathCache[cacheKey];
}
});
}
/****************************************************************************/ /****************************************************************************/
let readMetadata = require('./readMetadata.js'); let readMetadata = require('./readMetadata.js');
@ -147,6 +151,36 @@ function execute(port, options) {
}); });
} }
function startLiveReload() {
// Start LiveReload server.
process.env.NODE_ENV = 'development';
const server = tinylr();
server.listen(constants.LIVE_RELOAD_PORT, function() {
console.log(
'LiveReload server started on port %d',
constants.LIVE_RELOAD_PORT
);
});
// gaze watches some specified dirs and triggers a callback when they change.
gaze(
[
'../' + readMetadata.getDocsPath() + '/**/*', // docs
'**/*', // website
'!node_modules/**/*', // node_modules
],
function() {
// Listen for all kinds of file changes - modified/added/deleted.
this.on('all', function() {
// Notify LiveReload clients that there's a change.
// Typically, LiveReload will only refresh the changed paths,
// so we use / here to force a full-page reload.
server.notifyClients(['/']);
});
}
);
}
/****************************************************************************/ /****************************************************************************/
reloadMetadata(); reloadMetadata();
@ -200,13 +234,11 @@ function execute(port, options) {
} else { } else {
file = join(CWD, 'versioned_docs', metadata.source); file = join(CWD, 'versioned_docs', metadata.source);
} }
} else { } else if (!env.translation.enabled || metadata.language === 'en') {
if (!env.translation.enabled || 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);
} }
}
if (!fs.existsSync(file)) { if (!fs.existsSync(file)) {
next(); next();
@ -225,7 +257,7 @@ function execute(port, options) {
let defaultVersion = env.versioning.defaultVersion; let defaultVersion = env.versioning.defaultVersion;
// replace any links to markdown files to their website html links // replace any links to markdown files to their website html links
Object.keys(mdToHtml).forEach(function(key, index) { Object.keys(mdToHtml).forEach(key => {
let link = mdToHtml[key]; let link = mdToHtml[key];
link = utils.getPath(link, siteConfig.cleanUrl); link = utils.getPath(link, siteConfig.cleanUrl);
link = link.replace('/en/', '/' + language + '/'); link = link.replace('/en/', '/' + language + '/');
@ -333,8 +365,8 @@ function execute(port, options) {
); );
const str = renderToStaticMarkupWithDoctype(blogPageComp); const str = renderToStaticMarkupWithDoctype(blogPageComp);
let path = (page > 0 ? 'page' + (page + 1) : '') + '/index.html'; const pagePath = (page > 0 ? 'page' + (page + 1) : '') + '/index.html';
blogPages[path] = str; blogPages[pagePath] = str;
} }
let parts = req.path.toString().split('blog/'); let parts = req.path.toString().split('blog/');
@ -398,7 +430,7 @@ function execute(port, options) {
// handle all other main pages // handle all other main pages
app.get(pageRouting(siteConfig.baseUrl), (req, res, next) => { app.get(pageRouting(siteConfig.baseUrl), (req, res, next) => {
// look for user provided html file first // Look for user-provided HTML file first.
let htmlFile = req.path.toString().replace(siteConfig.baseUrl, ''); let htmlFile = req.path.toString().replace(siteConfig.baseUrl, '');
htmlFile = join(CWD, 'pages', htmlFile); htmlFile = join(CWD, 'pages', htmlFile);
if ( if (
@ -470,8 +502,8 @@ function execute(port, options) {
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' + sep); let userFileParts = userFile.split('pages' + sep);
let tempFile = join(__dirname, '..', 'pages', parts[1]); let tempFile = join(__dirname, '..', 'pages', userFileParts[1]);
tempFile = tempFile.replace( tempFile = tempFile.replace(
path.basename(file), path.basename(file),
'temp' + path.basename(file) 'temp' + path.basename(file)
@ -501,7 +533,6 @@ function execute(port, options) {
res.send(str); res.send(str);
} else { } else {
next(); next();
return;
} }
}); });
@ -598,36 +629,6 @@ function execute(port, options) {
if (options.watch) startLiveReload(); if (options.watch) startLiveReload();
app.listen(port); app.listen(port);
function startLiveReload() {
// Start LiveReload server.
process.env.NODE_ENV = 'development';
const server = tinylr();
server.listen(constants.LIVE_RELOAD_PORT, function() {
console.log(
'LiveReload server started on port %d',
constants.LIVE_RELOAD_PORT
);
});
// gaze watches some specified dirs and triggers a callback when they change.
gaze(
[
'../' + readMetadata.getDocsPath() + '/**/*', // docs
'**/*', // website
'!node_modules/**/*', // node_modules
],
function() {
// Listen for all kinds of file changes - modified/added/deleted.
this.on('all', function() {
// Notify LiveReload clients that there's a change.
// Typically, LiveReload will only refresh the changed paths,
// so we use / here to force a full-page reload.
server.notifyClients(['/']);
});
}
);
}
} }
module.exports = execute; module.exports = execute;

View file

@ -32,8 +32,6 @@ 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 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.
@ -48,25 +46,23 @@ module.exports = function(callback) {
// 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 => lang.enabled);
return lang.enabled == true;
});
} }
// create a url mapping to all the enabled languages files // Create a url mapping to all the enabled languages files
files.map(file => { const urls = files.map(file => {
let url = file.split('/pages/en')[1]; let url = file.split('/pages/en')[1];
url = siteConfig.cleanUrl url = siteConfig.cleanUrl
? url.replace(/\.js$/, '') ? url.replace(/\.js$/, '')
: url.replace(/\.js$/, '.html'); : url.replace(/\.js$/, '.html');
let links = enabledLanguages.map(lang => { const 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}); return {url, changefreq: 'weekly', priority: 0.5, links};
}); });
MetadataBlog.map(blog => { MetadataBlog.forEach(blog => {
urls.push({ urls.push({
url: '/blog/' + utils.getPath(blog.path, siteConfig.cleanUrl), url: '/blog/' + utils.getPath(blog.path, siteConfig.cleanUrl),
changefreq: 'weekly', changefreq: 'weekly',
@ -76,7 +72,7 @@ module.exports = function(callback) {
Object.keys(Metadata) Object.keys(Metadata)
.filter(key => Metadata[key].language === 'en') .filter(key => Metadata[key].language === 'en')
.map(key => { .forEach(key => {
let doc = Metadata[key]; let doc = Metadata[key];
let docUrl = utils.getPath(doc.permalink, siteConfig.cleanUrl); let docUrl = utils.getPath(doc.permalink, siteConfig.cleanUrl);
let links = enabledLanguages.map(lang => { let links = enabledLanguages.map(lang => {
@ -94,7 +90,7 @@ module.exports = function(callback) {
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,
}); });
sm.toXML((err, xml) => { sm.toXML((err, xml) => {

View file

@ -25,8 +25,8 @@ module.exports = function translatePlugin(babel) {
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(() => true).node.type === 'JSXElement') {
path.replaceWith( path.replaceWith(
t.jSXExpressionContainer( t.jSXExpressionContainer(
t.callExpression(t.identifier('translate'), [ t.callExpression(t.identifier('translate'), [

View file

@ -96,7 +96,7 @@ files.forEach(file => {
// returns the version to use for a document based on its id and // returns the version to use for a document based on its id and
// what the requested version is // what the requested version is
function docVersion(id, req_version) { function docVersion(id, reqVersion) {
if (!available[id]) { if (!available[id]) {
return null; return null;
} }
@ -104,13 +104,10 @@ function docVersion(id, req_version) {
// is found, then check if that version has an available file to use // is found, then check if that version has an available file to use
let requestedFound = false; let requestedFound = false;
for (let i = 0; i < versions.length; i++) { for (let i = 0; i < versions.length; i++) {
if (versions[i] === req_version) { if (versions[i] === reqVersion) {
requestedFound = true; requestedFound = true;
} }
if (!requestedFound) { if (requestedFound && available[id].has(versions[i])) {
continue;
}
if (available[id].has(versions[i])) {
return versions[i]; return versions[i];
} }
} }
@ -243,18 +240,16 @@ function docData() {
} }
// return the version of the sidebar to use given a requested version // return the version of the sidebar to use given a requested version
function sidebarVersion(req_version) { function sidebarVersion(reqVersion) {
// 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
// is found, then check if that version has an available file to use // is found, then check if that version has an available file to use
let requestedFound = false; let requestedFound = false;
for (let i = 0; i < versions.length; i++) { for (let i = 0; i < versions.length; i++) {
if (versions[i] === req_version) { if (versions[i] === reqVersion) {
requestedFound = true; requestedFound = true;
} }
if (!requestedFound) {
continue;
}
if ( if (
requestedFound &&
fs.existsSync( fs.existsSync(
CWD + '/versioned_sidebars/version-' + versions[i] + '-sidebars.json' CWD + '/versioned_sidebars/version-' + versions[i] + '-sidebars.json'
) )
@ -263,7 +258,7 @@ function sidebarVersion(req_version) {
} }
} }
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 ${reqVersion}. Verify that 'version-${reqVersion}-sidebars.json' exists.`
); );
} }

View file

@ -18,13 +18,12 @@ require('babel-register')({
presets: ['react', 'env'], presets: ['react', 'env'],
}); });
// For verifying port usage
const tcpPortUsed = require('tcp-port-used');
// initial check that required files are present
const chalk = require('chalk'); const chalk = require('chalk');
const fs = require('fs'); const fs = require('fs');
const program = require('commander');
const openBrowser = require('react-dev-utils/openBrowser'); const openBrowser = require('react-dev-utils/openBrowser');
const tcpPortUsed = require('tcp-port-used');
const CWD = process.cwd(); const CWD = process.cwd();
const env = require('./server/env.js'); const env = require('./server/env.js');
@ -40,8 +39,6 @@ if (env.versioning.enabled && env.versioning.missingVersionsPage) {
process.exit(1); process.exit(1);
} }
const program = require('commander');
program program
.option('--port <number>', 'Specify port number') .option('--port <number>', 'Specify port number')
.option('--no-watch', 'Toggle live reload file watching') .option('--no-watch', 'Toggle live reload file watching')
@ -50,7 +47,6 @@ program
let port = parseInt(program.port, 10) || process.env.PORT || 3000; let port = parseInt(program.port, 10) || process.env.PORT || 3000;
let numAttempts = 0; let numAttempts = 0;
const MAX_ATTEMPTS = 10; const MAX_ATTEMPTS = 10;
checkPort();
function checkPort() { function checkPort() {
tcpPortUsed tcpPortUsed
@ -84,3 +80,5 @@ function checkPort() {
}, 0); }, 0);
}); });
} }
checkPort();

View file

@ -7,11 +7,13 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const program = require('commander');
const chalk = require('chalk');
const glob = require('glob'); const glob = require('glob');
const fs = require('fs-extra'); const fs = require('fs-extra');
const path = require('path');
const mkdirp = require('mkdirp'); const mkdirp = require('mkdirp');
const chalk = require('chalk'); const path = require('path');
const readMetadata = require('./server/readMetadata.js'); const readMetadata = require('./server/readMetadata.js');
const utils = require('./server/utils.js'); const utils = require('./server/utils.js');
const versionFallback = require('./server/versionFallback.js'); const versionFallback = require('./server/versionFallback.js');
@ -28,7 +30,6 @@ if (fs.existsSync(CWD + '/versions.json')) {
let version; let version;
const program = require('commander');
program program
.arguments('<version>') .arguments('<version>')
.action(ver => { .action(ver => {
@ -130,16 +131,18 @@ if (versionFallback.diffLatestSidebar()) {
const versioned = {}; const versioned = {};
Object.keys(sidebar).forEach(sb => { Object.keys(sidebar).forEach(sb => {
const version_sb = 'version-' + version + '-' + sb; const versionSidebar = 'version-' + version + '-' + sb;
versioned[version_sb] = {}; versioned[versionSidebar] = {};
const categories = sidebar[sb]; const categories = sidebar[sb];
Object.keys(categories).forEach(category => { Object.keys(categories).forEach(category => {
versioned[version_sb][category] = []; versioned[versionSidebar][category] = [];
const ids = categories[category]; const ids = categories[category];
ids.forEach((id, index) => { ids.forEach(id => {
versioned[version_sb][category].push('version-' + version + '-' + id); versioned[versionSidebar][category].push(
'version-' + version + '-' + id
);
}); });
}); });
}); });

View file

@ -9,15 +9,16 @@
/* generate the i18n/en.json file */ /* generate the i18n/en.json file */
const CWD = process.cwd();
const fs = require('fs-extra');
const mkdirp = require('mkdirp');
const glob = require('glob');
const readMetadata = require('./server/readMetadata.js');
const path = require('path');
const siteConfig = require(CWD + '/siteConfig.js');
const babylon = require('babylon');
const traverse = require('babel-traverse').default; const traverse = require('babel-traverse').default;
const babylon = require('babylon');
const fs = require('fs-extra');
const glob = require('glob');
const mkdirp = require('mkdirp');
const nodePath = require('path');
const readMetadata = require('./server/readMetadata.js');
const CWD = process.cwd();
const siteConfig = require(CWD + '/siteConfig.js');
const sidebars = require(CWD + '/sidebars.json'); const sidebars = require(CWD + '/sidebars.json');
let customTranslations = { let customTranslations = {
@ -46,10 +47,10 @@ function execute() {
}; };
// look through markdown headers of docs for titles and categories to translate // look through markdown headers of docs for titles and categories to translate
const docsDir = path.join(CWD, '../', readMetadata.getDocsPath()); const docsDir = nodePath.join(CWD, '../', readMetadata.getDocsPath());
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 = nodePath.extname(file);
if (extension === '.md' || extension === '.markdown') { if (extension === '.md' || extension === '.markdown') {
let res; let res;
try { try {
@ -115,7 +116,7 @@ function execute() {
// 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 = nodePath.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'],

View file

@ -5,29 +5,56 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
const React = require("react"); /* eslint-disable react/jsx-no-comment-textnodes */
const CompLibrary = require("../../core/CompLibrary.js");
const React = require('react');
const CompLibrary = require('../../core/CompLibrary.js');
const Container = CompLibrary.Container; const Container = CompLibrary.Container;
const GridBlock = CompLibrary.GridBlock; const siteConfig = require(process.cwd() + '/siteConfig.js');
const siteConfig = require(process.cwd() + "/siteConfig.js"); const translate = require('../../server/translate.js').translate;
const translate = require("../../server/translate.js").translate;
class AboutSlash extends React.Component { class AboutSlash extends React.Component {
render() { render() {
return ( return (
<div className="pageContainer"> <div className="pageContainer">
<Container className="mainContainer documentContainer postContainer"> <Container className="mainContainer documentContainer postContainer">
<h1><translate>About Slash</translate></h1> <h1>
<img src={`${siteConfig.baseUrl}img/docusaurus.svg`} alt="Docusaurus"/> <translate>About Slash</translate>
</h1>
<img
src={`${siteConfig.baseUrl}img/docusaurus.svg`}
alt="Docusaurus"
/>
<p> <p>
Slash is the official mascot of Docusaurus. You will find different variations of her throughout the <a href="https://docusaurus.io">website</a>, whether she is moving fast on her scooter or writing documentation at her standing desk. At Facebook, we have actual Slash plushies -- and you never know, you may see these plushies at various events and conferences in the future. Slash is the official mascot of Docusaurus. You will find different
variations of her throughout the{' '}
<a href="https://docusaurus.io">website</a>, whether she is moving
fast on her scooter or writing documentation at her standing desk.
At Facebook, we have actual Slash plushies -- and you never know,
you may see these plushies at various events and conferences in the
future.
</p> </p>
</Container> </Container>
<Container className="mainContainer"> <Container className="mainContainer">
<h2><translate>Birth of Slash</translate></h2> <h2>
<img src={`${siteConfig.baseUrl}img/slash-birth.png`} alt="Birth of Slash"/> <translate>Birth of Slash</translate>
</h2>
<img
src={`${siteConfig.baseUrl}img/slash-birth.png`}
alt="Birth of Slash"
/>
<p> <p>
The team sat in a conference room trying to come up with a name for the project. Dinosaurs became a theme, finally landing on Docusaurus, combining documentation with those many dinosaurs that end in "saurus". Of course, we needed a logo for our new project. Eric sat down and designed a logo that was quite beyond the norm of our normal open source project logos, but yet was just so awesome, we had to use it. We needed a name for this cute Docusaur. "Marky" for markdown? "Docky" for documentation? No, "Slash" for the normal way someone starts code documentation in many programming languages <code>//</code> or <code>/*</code> or <code>///</code>. And Slash was born. The team sat in a conference room trying to come up with a name for
the project. Dinosaurs became a theme, finally landing on
Docusaurus, combining documentation with those many dinosaurs that
end in "saurus". Of course, we needed a logo for our new project.
Eric sat down and designed a logo that was quite beyond the norm of
our normal open source project logos, but yet was just so awesome,
we had to use it. We needed a name for this cute Docusaur. "Marky"
for markdown? "Docky" for documentation? No, "Slash" for the normal
way someone starts code documentation in many programming languages{' '}
<code>//</code> or <code>/*</code> or <code>///</code>. And Slash
was born.
</p> </p>
</Container> </Container>
<br /> <br />
@ -37,7 +64,7 @@ class AboutSlash extends React.Component {
} }
AboutSlash.defaultProps = { AboutSlash.defaultProps = {
language: "en" language: 'en',
}; };
AboutSlash.title = 'About Slash'; AboutSlash.title = 'About Slash';

View file

@ -9,7 +9,6 @@ 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 MarkdownBlock = CompLibrary.MarkdownBlock; /* Used to read markdown */
const siteConfig = require(process.cwd() + '/siteConfig.js'); const siteConfig = require(process.cwd() + '/siteConfig.js');
const translate = require('../../server/translate.js').translate; const translate = require('../../server/translate.js').translate;
@ -74,17 +73,11 @@ 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 => user.pinned).map(user => (
.filter(user => { <a href={user.infoLink} key={user.infoLink}>
return user.pinned;
})
.map((user, i) => {
return (
<a href={user.infoLink} key={i}>
<img src={user.image} alt={user.caption} title={user.caption} /> <img src={user.image} alt={user.caption} title={user.caption} />
</a> </a>
); ));
});
return ( return (
<div> <div>

View file

@ -12,9 +12,9 @@ const siteConfig = require(process.cwd() + '/siteConfig.js');
const translate = require('../../server/translate.js').translate; const translate = require('../../server/translate.js').translate;
class Users extends React.Component { class Users extends React.Component {
renderUser(user, i) { renderUser(user) {
return ( return (
<a href={user.infoLink} key={i}> <a href={user.infoLink} key={user.infoLink}>
<img src={user.image} alt={user.caption} title={user.caption} /> <img src={user.image} alt={user.caption} title={user.caption} />
</a> </a>
); );

View file

@ -4,6 +4,7 @@ window.addEventListener('load', function() {
function button(label, ariaLabel, icon, className) { function button(label, ariaLabel, icon, className) {
const btn = document.createElement('button'); const btn = document.createElement('button');
btn.classList.add('btnIcon', className); btn.classList.add('btnIcon', className);
btn.setAttribute('type', 'button');
btn.setAttribute('aria-label', ariaLabel); btn.setAttribute('aria-label', ariaLabel);
btn.innerHTML = btn.innerHTML =
'<div class="btnIcon__body">' + '<div class="btnIcon__body">' +
@ -11,8 +12,7 @@ window.addEventListener('load', function() {
'<strong class="btnIcon__label">' + '<strong class="btnIcon__label">' +
label + label +
'</strong>' + '</strong>' +
'</div>' + '</div>';
'</button>';
return btn; return btn;
} }