From 3598dffc584fc0c06ea5f10dd0472e0e2e43d666 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 3 Aug 2017 10:25:01 -0700 Subject: [PATCH 01/10] Add versioning functionality --- lib/core/Doc.js | 4 +- lib/core/DocsLayout.js | 1 + lib/core/Site.js | 1 + lib/core/nav/HeaderNav.js | 18 ++- lib/core/nav/SideNav.js | 3 +- lib/server/generate.js | 161 +++++++++----------- lib/server/readCategories.js | 8 +- lib/server/readMetadata.js | 34 ++++- lib/server/server.js | 71 ++++++--- lib/server/versionFallback.js | 278 ++++++++++++++++++++++++++++++++++ lib/version.js | 116 ++++++++++++++ package.json | 5 +- 12 files changed, 568 insertions(+), 132 deletions(-) create mode 100644 lib/server/versionFallback.js create mode 100644 lib/version.js diff --git a/lib/core/Doc.js b/lib/core/Doc.js index af94208ffc..5c76503296 100644 --- a/lib/core/Doc.js +++ b/lib/core/Doc.js @@ -13,7 +13,7 @@ const Marked = require("./Marked.js"); class Doc extends React.Component { render() { let editLink = - this.props.config.editUrl && + !this.props.version && this.props.config.editUrl && ; if (this.props.language != "en") { editLink = - this.props.config.recruitingLink && + !this.props.version && this.props.config.recruitingLink &&
diff --git a/lib/core/Site.js b/lib/core/Site.js index 8c6c70011c..f499bb3934 100644 --- a/lib/core/Site.js +++ b/lib/core/Site.js @@ -78,6 +78,7 @@ class Site extends React.Component { section={this.props.section} title={this.props.config.title} language={this.props.language} + version={this.props.version} />
{this.props.children} diff --git a/lib/core/nav/HeaderNav.js b/lib/core/nav/HeaderNav.js index ae7663bf2d..bf2b128486 100644 --- a/lib/core/nav/HeaderNav.js +++ b/lib/core/nav/HeaderNav.js @@ -92,14 +92,22 @@ class HeaderNav extends React.Component { } makeInternalLinks(link) { - const linkWithLang = link.href.replace( + let updatedLink = link.href.replace( /\/LANGUAGE\//, "/" + this.props.language + "/" ); + if (this.props.version) { + updatedLink = updatedLink.replace( + /\/VERSION\//, + "/" + this.props.version + "/" + ); + } else { + updatedLink = updatedLink.replace(/\/VERSION\//, "/"); + } return (
  • {translation[this.props.language] @@ -111,14 +119,10 @@ class HeaderNav extends React.Component { } makeExternalLinks(link) { - const linkWithLang = link.href.replace( - /\/LANGUAGE\//, - "/" + this.props.language + "/" - ); return (
  • diff --git a/lib/core/nav/SideNav.js b/lib/core/nav/SideNav.js index 3ab9b04ec3..dfb128df34 100644 --- a/lib/core/nav/SideNav.js +++ b/lib/core/nav/SideNav.js @@ -78,8 +78,9 @@ class SideNav extends React.Component { ? i18n["localized-strings"][sbTitle] || sbTitle : sbTitle; } else { + const id = metadata.original_id || metadata.localized_id; localizedString = i18n - ? i18n["localized-strings"][metadata.localized_id] || metadata.title + ? i18n["localized-strings"][id] || metadata.title : metadata.title; } return localizedString; diff --git a/lib/server/generate.js b/lib/server/generate.js index 16965dcc54..d7f05ad8b1 100644 --- a/lib/server/generate.js +++ b/lib/server/generate.js @@ -20,6 +20,9 @@ function execute() { const Site = require("../core/Site.js"); const siteConfig = require(CWD + "/siteConfig.js"); const translate = require("./translate.js"); + const versionFallback = require("./versionFallback.js"); + + const ENABLE_TRANSLATION = fs.existsSync(CWD + "/languages.js"); let languages; if (fs.existsSync(CWD + "/languages.js")) { languages = require(CWD + "/languages.js"); @@ -77,114 +80,86 @@ function execute() { readMetadata.generateDocsMetadata(); const Metadata = require("../core/metadata.js"); - let mdToHtml = {}; - for (let i = 0; i < Metadata.length; i++) { - const metadata = Metadata[i]; - if (metadata.language !== "en") { - continue; + + const mdToHtml = {}; + Object.keys(Metadata).forEach(id => { + const metadata = Metadata[id]; + if (metadata.language !== "en" || metadata.version) { + return; } - mdToHtml[metadata.source] = siteConfig.baseUrl + metadata.permalink; - } + let htmlLink = siteConfig.baseUrl + metadata.permalink; + if (htmlLink.includes("/docs/en/")) { + htmlLink = htmlLink.replace("/docs/en/", "/docs/en/VERSION/"); + } else { + htmlLink = htmlLink.replace("/docs/", "/docs/VERSION/"); + } + mdToHtml[metadata.source] = htmlLink; + }); const DocsLayout = require("../core/DocsLayout.js"); fs.removeSync(CWD + "/build"); - // create html files for all English docs - let files = glob.sync(CWD + "/../docs/**"); - files.forEach(file => { - // console.log(file); - let language = "en"; + // create html files for all docs + Object.keys(Metadata).forEach(id => { + const metadata = Metadata[id]; - const extension = path.extname(file); - - if (extension === ".md" || extension === ".markdown") { - const result = readMetadata.processMetadata(file); - if (!result) { - return; + let file; + if (metadata.version) { + if (ENABLE_TRANSLATION) { + file = + CWD + "/versioned_docs/" + metadata.language + "/" + metadata.source; + } else { + file = CWD + "/versioned_docs/" + metadata.source; } - - const metadata = result.metadata; - let rawContent = result.rawContent; - - /* generate table of contents if appropriate */ - if (rawContent && rawContent.indexOf(TABLE_OF_CONTENTS_TOKEN) != -1) { - rawContent = insertTableOfContents(rawContent); + } else { + if (metadata.language === "en") { + file = CWD + "/../docs/" + metadata.source; + } else { + file = + CWD + "/translated_docs/" + metadata.language + "/" + metadata.source; } - - /* replace any links to markdown files to their website html links */ - Object.keys(mdToHtml).forEach(function(key, index) { - rawContent = rawContent.replace( - new RegExp(key, "g"), - mdToHtml[key].replace("/en/", "/" + language + "/") - ); - }); - - const docComp = ( - - {rawContent} - - ); - const str = renderToStaticMarkup(docComp); - - let targetFile = - CWD + "/build/" + siteConfig.projectName + "/" + metadata.permalink; - // console.log(targetFile); - writeFileAndCreateFolder(targetFile, str); } - }); + if (!fs.existsSync(file)) { + return; + } + let rawContent = readMetadata.extractMetadata(fs.readFileSync(file, "utf8")) + .rawContent; - // create html files for all non-English docs - if (languages.length > 1) { - files = glob.sync(CWD + "/translated_docs/**"); - files.forEach(file => { - let language = "en"; + const language = metadata.language; - const regexSubFolder = /translated_docs\/(.*)\/.*/; - const match = regexSubFolder.exec(file); - if (match) { - language = match[1]; - } + /* generate table of contents if appropriate */ + if (rawContent && rawContent.indexOf(TABLE_OF_CONTENTS_TOKEN) != -1) { + rawContent = insertTableOfContents(rawContent); + } - if (enabledLanguages.indexOf(language) === -1) { - return; - } - - const extension = path.extname(file); - if (extension !== ".md" && extension !== ".markdown") { - return; - } - - const result = readMetadata.processMetadata(file); - if (!result) { - return; - } - - const metadata = result.metadata; - let rawContent = result.rawContent; - - /* generate table of contents if appropriate */ - if (rawContent && rawContent.indexOf(TABLE_OF_CONTENTS_TOKEN) != -1) { - rawContent = insertTableOfContents(rawContent); - } - - /* replace any links to markdown files to their website html links */ - Object.keys(mdToHtml).forEach(function(key, index) { - rawContent = rawContent.replace(new RegExp(key, "g"), mdToHtml[key]); - }); - - const docComp = ( - - {rawContent} - + /* replace any links to markdown files to their website html links */ + Object.keys(mdToHtml).forEach(function(key, index) { + let link = mdToHtml[key]; + link = link.replace("/en/", "/" + language + "/"); + link = link.replace( + "/VERSION/", + metadata.version ? "/" + metadata.version + "/" : "/" ); - const str = renderToStaticMarkup(docComp); - let targetFile = - CWD + "/build/" + siteConfig.projectName + "/" + metadata.permalink; - // console.log(targetFile); - writeFileAndCreateFolder(targetFile, str); + rawContent = rawContent.replace(new RegExp(key, "g"), link); }); - } + + rawContent = rawContent.replace( + /\]\(assets\//g, + "](" + siteConfig.baseUrl + "docs/assets/" + ); + + const docComp = ( + + {rawContent} + + ); + const str = renderToStaticMarkup(docComp); + const targetFile = + CWD + "/build/" + siteConfig.projectName + "/" + metadata.permalink; + + writeFileAndCreateFolder(targetFile, str); + }); /* copy docs assets if they exist */ if (fs.existsSync(CWD + "/../docs/assets")) { diff --git a/lib/server/readCategories.js b/lib/server/readCategories.js index 2ae0d04875..c90310992e 100644 --- a/lib/server/readCategories.js +++ b/lib/server/readCategories.js @@ -34,8 +34,12 @@ function readCategories(sidebar) { for (let k = 0; k < enabledLanguages.length; ++k) { const language = enabledLanguages[k]; - const metadatas = Metadata.filter(metadata => { - return metadata.sidebar === sidebar && metadata.language === language; + const metadatas = []; + Object.keys(Metadata).forEach(id => { + const metadata = Metadata[id]; + if (metadata.sidebar === sidebar && metadata.language === language) { + metadatas.push(metadata); + } }); // Build a hashmap of article_id -> metadata diff --git a/lib/server/readMetadata.js b/lib/server/readMetadata.js index efc31d8f65..7b7f4614b0 100644 --- a/lib/server/readMetadata.js +++ b/lib/server/readMetadata.js @@ -14,6 +14,7 @@ const fs = require("fs"); const os = require("os"); const glob = require("glob"); const siteConfig = require(CWD + "/siteConfig.js"); +const versionFallback = require("./versionFallback"); let languages; if (fs.existsSync(CWD + "/languages.js")) { languages = require(CWD + "/languages.js"); @@ -28,7 +29,9 @@ if (fs.existsSync(CWD + "/languages.js")) { } function readSidebar() { - const allSidebars = require(CWD + "/sidebar.json"); + let allSidebars = require(CWD + "/sidebar.json"); + Object.assign(allSidebars, versionFallback.sidebarData()); + const order = {}; Object.keys(allSidebars).forEach(sidebar => { @@ -148,7 +151,7 @@ function generateDocsMetadata() { enabledLanguages.push(lang.tag); }); - const metadatas = []; + const metadatas = {}; /* metadata for english files */ let files = glob.sync(CWD + "/../docs/**"); @@ -163,7 +166,7 @@ function generateDocsMetadata() { return; } let metadata = res.metadata; - metadatas.push(metadata); + metadatas[metadata.id] = metadata; } }); @@ -188,10 +191,32 @@ function generateDocsMetadata() { return; } let metadata = res.metadata; - metadatas.push(metadata); + metadatas[metadata.id] = metadata; } }); + versionData = versionFallback.docData(); + versionData.forEach(metadata => { + const id = metadata.localized_id; + metadata.sidebar = order[id].sidebar; + metadata.category = order[id].category; + if (order[id].next) { + metadata.next_id = order[id].next.replace( + "version-" + metadata.version + "-", + "" + ); + metadata.next = metadata.language + "-" + order[id].next; + } + if (order[id].previous) { + metadata.previous_id = order[id].previous.replace( + "version-" + metadata.version + "-", + "" + ); + metadata.previous = metadata.language + "-" + order[id].previous; + } + metadatas[metadata.id] = metadata; + }); + fs.writeFileSync( __dirname + "/../core/metadata.js", "/**\n" + @@ -245,6 +270,7 @@ function generateBlogMetadata() { } module.exports = { + readSidebar, extractMetadata, processMetadata, generateDocsMetadata, diff --git a/lib/server/server.js b/lib/server/server.js index 85a62e5048..e0fe145f15 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -20,6 +20,7 @@ function execute(port) { const mkdirp = require("mkdirp"); const glob = require("glob"); const translate = require("./translate.js"); + const versionFallback = require("./versionFallback"); const CWD = process.cwd(); const ENABLE_TRANSLATION = fs.existsSync(CWD + "/languages.js"); @@ -127,37 +128,59 @@ function execute(port) { purgeCache(CWD + "/siteConfig.js"); siteConfig = require(CWD + "/siteConfig.js"); + let url = req.path.toString().replace(siteConfig.baseUrl, ""); + reloadMetadata(); + + // links is a map from a permalink to an id let links = {}; - for (let i = 0; i < Metadata.length; i++) { - const metadata = Metadata[i]; - if (metadata.language === "en") { - links[metadata.permalink] = CWD + "/../docs/" + metadata.source; + Object.keys(Metadata).forEach(id => { + const metadata = Metadata[id]; + links[metadata.permalink] = id; + }); + + const mdToHtml = {}; + Object.keys(Metadata).forEach(id => { + const metadata = Metadata[id]; + if (metadata.language !== "en" || metadata.version) { + return; + } + let htmlLink = siteConfig.baseUrl + metadata.permalink; + if (htmlLink.includes("/docs/en/")) { + htmlLink = htmlLink.replace("/docs/en/", "/docs/en/VERSION/"); } else { - links[metadata.permalink] = + htmlLink = htmlLink.replace("/docs/", "/docs/VERSION/"); + } + mdToHtml[metadata.source] = htmlLink; + }); + + const metadata = Metadata[links[url]]; + const language = metadata.language; + + let file; + if (metadata.version) { + if (ENABLE_TRANSLATION) { + file = + CWD + "/versioned_docs/" + metadata.language + "/" + metadata.source; + } else { + file = CWD + "/versioned_docs/" + metadata.source; + } + } else { + if (metadata.language === "en") { + file = CWD + "/../docs/" + metadata.source; + } else { + file = CWD + "/translated_docs/" + metadata.language + "/" + metadata.source; } } - let mdToHtml = {}; - for (let i = 0; i < Metadata.length; i++) { - const metadata = Metadata[i]; - if (metadata.language !== "en") { - continue; - } - mdToHtml[metadata.source] = siteConfig.baseUrl + metadata.permalink; - } - - let file = links[req.path.toString().replace(siteConfig.baseUrl, "")]; if (!fs.existsSync(file)) { next(); return; } - const result = readMetadata.processMetadata(file); - const metadata = result.metadata; - const language = metadata.language; - let rawContent = result.rawContent; + let rawContent = readMetadata.extractMetadata(fs.readFileSync(file, "utf8")) + .rawContent; /* generate table of contents if appropriate */ if (rawContent && rawContent.indexOf(TABLE_OF_CONTENTS_TOKEN) !== -1) { @@ -166,10 +189,13 @@ function execute(port) { /* replace any links to markdown files to their website html links */ Object.keys(mdToHtml).forEach(function(key, index) { - rawContent = rawContent.replace( - new RegExp(key, "g"), - mdToHtml[key].replace("/en/", "/" + language + "/") + let link = mdToHtml[key]; + link = link.replace("/en/", "/" + language + "/"); + link = link.replace( + "/VERSION/", + metadata.version ? "/" + metadata.version + "/" : "/" ); + rawContent = rawContent.replace(new RegExp(key, "g"), link); }); rawContent = rawContent.replace( @@ -187,6 +213,7 @@ function execute(port) { res.send(renderToStaticMarkup(docComp)); }); + /* handle all requests for blog pages and posts */ app.get(/blog\/.*html$/, (req, res) => { purgeCache(CWD + "/siteConfig.js"); diff --git a/lib/server/versionFallback.js b/lib/server/versionFallback.js new file mode 100644 index 0000000000..1150f2e890 --- /dev/null +++ b/lib/server/versionFallback.js @@ -0,0 +1,278 @@ +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const CWD = process.cwd(); +const semver = require("semver"); +const glob = require("glob"); +const fs = require("fs"); +const path = require("path"); +const diff = require("diff"); +const assert = require("assert"); +const siteConfig = require(CWD + "/siteConfig.js"); + +const ENABLE_TRANSLATION = fs.existsSync(CWD + "/languages.js"); +let languages; +if (fs.existsSync(CWD + "/languages.js")) { + languages = require(CWD + "/languages.js"); +} else { + languages = [ + { + enabled: true, + name: "English", + tag: "en" + } + ]; +} + +/*****************************************************************/ + +// included to prevent cyclical dependency with readMetadata.js + +function splitHeader(content) { + const lines = content.split("\n"); + let i = 1; + for (; i < lines.length - 1; ++i) { + if (lines[i] === "---") { + break; + } + } + return { + header: lines.slice(1, i + 1).join("\n"), + content: lines.slice(i + 1).join("\n") + }; +} + +// Extract markdown metadata header +function extractMetadata(content) { + const metadata = {}; + const both = splitHeader(content); + const lines = both.header.split("\n"); + for (let i = 0; i < lines.length - 1; ++i) { + const keyvalue = lines[i].split(":"); + const key = keyvalue[0].trim(); + let value = keyvalue.slice(1).join(":").trim(); + // Handle the case where you have "Community #10" + try { + value = JSON.parse(value); + } catch (e) {} + metadata[key] = value; + } + return { metadata, rawContent: both.content }; +} + +/*****************************************************************/ + +/* preprocessing */ +const versions = []; +const versionFolder = ENABLE_TRANSLATION + ? CWD + "/versioned_docs/en/" + : CWD + "/versioned_docs/"; +let files = glob.sync(versionFolder + "*"); +files.forEach(file => { + if (!fs.lstatSync(file).isDirectory()) { + return; + } + const version = file.split("version-")[1]; + versions.push(version); +}); +versions.sort(semver.rcompare); + +const available = {}; +const versionFiles = {}; +files = glob.sync(versionFolder + "**"); +files.forEach(file => { + const ext = path.extname(file); + if (ext !== ".md" && ext !== ".markdown") { + return; + } + const res = extractMetadata(fs.readFileSync(file, "utf8")); + const metadata = res.metadata; + + if (!(metadata.original_id in available)) { + available[metadata.original_id] = new Set(); + } + const version = metadata.id.split("-")[1]; + available[metadata.original_id].add(version); + + if (!(version in versionFiles)) { + versionFiles[version] = {}; + } + versionFiles[version][metadata.original_id] = file; +}); + +function docVersion(id, req_version) { + for (let i = 0; i < versions.length; i++) { + if (semver.gt(versions[i], req_version)) { + continue; + } + if (!available[id]) { + return null; + } + if (available[id].has(versions[i])) { + return versions[i]; + } + } + return null; +} + +function diffLatestDoc(file, id) { + if (versions.length === 0) { + return true; + } + + const latest = versions[0]; + + const version = docVersion(id, latest); + if (!version) { + return true; + } + const latestFile = versionFiles[version][id]; + + if (!latestFile || !fs.existsSync(latestFile)) { + return true; + } + + const diffs = diff.diffChars( + extractMetadata(fs.readFileSync(latestFile, "utf8")).rawContent, + extractMetadata(fs.readFileSync(file, "utf8")).rawContent + ); + diffs.forEach(part => { + if (part.added || part.removed) { + return true; + } + }); + return false; +} + +function processVersionMetadata(file, version, useVersion, language) { + const metadata = extractMetadata(fs.readFileSync(file, "utf8")).metadata; + metadata.source = "version-" + useVersion + "/" + path.basename(file); + if (!ENABLE_TRANSLATION && !siteConfig.useEnglishUrl) { + metadata.permalink = + "docs/" + version + "/" + metadata.original_id + ".html"; + } else { + metadata.permalink = + "docs/" + language + "/" + version + "/" + metadata.original_id + ".html"; + } + metadata.id = metadata.id.replace( + "version-" + useVersion + "-", + "version-" + version + "-" + ); + metadata.localized_id = metadata.id; + metadata.id = language + "-" + metadata.id; + metadata.language = language; + metadata.version = version; + + return metadata; +} + +function docData() { + const files = glob.sync(CWD + "/versioned_docs/**"); + + allIds = new Set(); + Object.keys(versionFiles).forEach(version => { + Object.keys(versionFiles[version]).forEach(id => { + allIds.add(id); + }); + }); + + const metadatas = []; + + languages.filter(language => language.enabled).forEach(language => { + versions.forEach(version => { + allIds.forEach(id => { + const useVersion = docVersion(id, version); + if (!useVersion) { + return; + } + const file = versionFiles[useVersion][id]; + + metadatas.push( + processVersionMetadata(file, version, useVersion, language.tag) + ); + }); + }); + }); + + return metadatas; +} + +function sidebarVersion(req_version) { + for (let i = 0; i < versions.length; i++) { + if (semver.gt(versions[i], req_version)) { + continue; + } + if ( + fs.existsSync( + CWD + "/versioned_sidebars/version-" + versions[i] + "-sidebar.json" + ) + ) { + return versions[i]; + } + } + return null; +} + +function diffLatestSidebar() { + if (versions.length === 0) { + return true; + } + const latest = versions[0]; + + const version = sidebarVersion(latest); + const latestSidebar = + CWD + "/versioned_sidebars/version-" + version + "-sidebar.json"; + if (!fs.existsSync(latestSidebar)) { + return true; + } + const currentSidebar = CWD + "/sidebar.json"; + if (!fs.existsSync(currentSidebar)) { + // TO DO: error message + } + + // compare for equality between latest version sidebar with version prefixes + // stripped and current sidebar + return ( + JSON.stringify(JSON.parse(fs.readFileSync(latestSidebar, "utf8"))).replace( + new RegExp("version-" + version + "-", "g"), + "" + ) !== JSON.stringify(JSON.parse(fs.readFileSync(currentSidebar, "utf8"))) + ); +} + +function sidebarData() { + const allSidebars = {}; + + for (let i = 0; i < versions.length; i++) { + const version = sidebarVersion(versions[i]); + const sidebar = JSON.parse( + fs + .readFileSync( + CWD + "/versioned_sidebars/version-" + version + "-sidebar.json", + "utf8" + ) + .replace( + new RegExp("version-" + version + "-", "g"), + "version-" + versions[i] + "-" + ) + ); + Object.assign(allSidebars, sidebar); + } + return allSidebars; +} + +module.exports = { + docVersion, + diffLatestDoc, + processVersionMetadata, + docData, + sidebarVersion, + diffLatestSidebar, + sidebarData +}; diff --git a/lib/version.js b/lib/version.js new file mode 100644 index 0000000000..54c8e91999 --- /dev/null +++ b/lib/version.js @@ -0,0 +1,116 @@ +#!/usr/bin/env node + +/** + * Copyright (c) 2017-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +const CWD = process.cwd(); +const glob = require("glob"); +const fs = require("fs-extra"); +const path = require("path"); +const mkdirp = require("mkdirp"); +const semver = require("semver"); +const readMetadata = require("./server/readMetadata.js"); +const versionFallback = require("./server/versionFallback.js"); + +const ENABLE_TRANSLATION = fs.existsSync(CWD + "/languages.js"); + +let version; + +const program = require("commander"); +program + .arguments("") + .action(ver => { + version = ver; + }) + .parse(process.argv); + +if (typeof version === "undefined") { + console.error( + "No version number specified!\nPass the version you wish to create as an argument.\nEx: 1.0.0" + ); + process.exit(1); +} + +if (!(version = semver.valid(version))) { + console.error( + "Invalid version!\nSpecify a valid version following the specifications at http://semver.org/." + ); + process.exit(1); +} + +function makeHeader(metadata) { + let header = "---\n"; + Object.keys(metadata).forEach(key => { + header += key + ": " + metadata[key] + "\n"; + }); + header += "---\n"; + return header; +} + +let versionFolder = CWD + "/versioned_docs/version-" + version; +if (ENABLE_TRANSLATION) { + versionFolder = CWD + "/versioned_docs/en/version-" + version; +} +mkdirp.sync(versionFolder); + +let files = glob.sync(CWD + "/../docs/*"); +files.forEach(file => { + const ext = path.extname(file); + if (ext !== ".md" && ext !== ".markdown") { + return; + } + + const res = readMetadata.extractMetadata(fs.readFileSync(file, "utf8")); + let metadata = res.metadata; + let rawContent = res.rawContent; + if (!metadata.id) { + return; + } + + if (!versionFallback.diffLatestDoc(file, metadata.id)) { + return; + } + + metadata.original_id = metadata.id; + metadata.id = "version-" + version + "-" + metadata.id; + + let targetFile = + CWD + "/versioned_docs/version-" + version + "/" + path.basename(file); + if (ENABLE_TRANSLATION) { + targetFile = CWD + "/versioned_docs/en/version-" + version + "/" + path.basename(file); + } + fs.writeFileSync(targetFile, makeHeader(metadata) + rawContent, "utf8"); +}); + +if (versionFallback.diffLatestSidebar()) { + mkdirp(CWD + "/versioned_sidebars"); + const sidebar = JSON.parse(fs.readFileSync(CWD + "/sidebar.json", "utf8")); + const versioned = {}; + + Object.keys(sidebar).forEach(sb => { + const version_sb = "version-" + version + "-" + sb; + versioned[version_sb] = {}; + + const categories = sidebar[sb]; + Object.keys(categories).forEach(category => { + versioned[version_sb][category] = []; + + const ids = categories[category]; + ids.forEach((id, index) => { + versioned[version_sb][category].push("version-" + version + "-" + id); + }); + }); + }); + + fs.writeFileSync( + CWD + "/versioned_sidebars/version-" + version + "-sidebar.json", + JSON.stringify(versioned, null, 2), + "utf8" + ); +} diff --git a/package.json b/package.json index a110562666..03a9ca9bc7 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "babylon": "^6.17.4", "classnames": "^2.2.5", "commander": "^2.11.0", + "diff": "^3.3.0", "express": "^4.15.3", "fs-extra": "^3.0.1", "glob": "^7.1.2", @@ -19,6 +20,7 @@ "react": "^15.5.4", "react-dom": "^15.5.4", "request": "^2.81.0", + "semver": "^5.4.1", "shelljs": "^0.7.8" }, "name": "docusaurus", @@ -28,6 +30,7 @@ "docusaurus-build": "./lib/build-files.js", "docusaurus-publish": "./lib/publish-gh-pages.js", "docusaurus-examples": "./lib/copy-examples.js", - "docusaurus-write-translations": "./lib/write-translations.js" + "docusaurus-write-translations": "./lib/write-translations.js", + "docusaurus-version": "./lib/version.js" } } From d3e3d209a47f615812bea88ce9f6f8baecfc1dc3 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 3 Aug 2017 11:14:56 -0700 Subject: [PATCH 02/10] Add comments for new versioning files --- lib/server/versionFallback.js | 17 ++++++++++++++++- lib/version.js | 5 ++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/server/versionFallback.js b/lib/server/versionFallback.js index 1150f2e890..4683ea7d48 100644 --- a/lib/server/versionFallback.js +++ b/lib/server/versionFallback.js @@ -68,7 +68,7 @@ function extractMetadata(content) { /*****************************************************************/ -/* preprocessing */ +// versions is an array of all versions currently in use const versions = []; const versionFolder = ENABLE_TRANSLATION ? CWD + "/versioned_docs/en/" @@ -83,7 +83,11 @@ files.forEach(file => { }); versions.sort(semver.rcompare); +// available stores doc ids of documents that are available for +// each version const available = {}; +// versionFiles is used to keep track of what file to use with a +// given version/id of a document const versionFiles = {}; files = glob.sync(versionFolder + "**"); files.forEach(file => { @@ -106,6 +110,8 @@ files.forEach(file => { versionFiles[version][metadata.original_id] = file; }); +// returns the version to use for a document based on its id and +// what the requested version is function docVersion(id, req_version) { for (let i = 0; i < versions.length; i++) { if (semver.gt(versions[i], req_version)) { @@ -121,6 +127,8 @@ function docVersion(id, req_version) { return null; } +// returns whether a given file has content that differ from the +// document with the given id function diffLatestDoc(file, id) { if (versions.length === 0) { return true; @@ -150,6 +158,8 @@ function diffLatestDoc(file, id) { return false; } +// return metadata for a versioned file given the file, its version (requested), +// the version of the file to be used, and its language function processVersionMetadata(file, version, useVersion, language) { const metadata = extractMetadata(fs.readFileSync(file, "utf8")).metadata; metadata.source = "version-" + useVersion + "/" + path.basename(file); @@ -172,6 +182,7 @@ function processVersionMetadata(file, version, useVersion, language) { return metadata; } +// return all metadata of versioned documents function docData() { const files = glob.sync(CWD + "/versioned_docs/**"); @@ -203,6 +214,7 @@ function docData() { return metadatas; } +// return the version of the sidebar to use given a requested version function sidebarVersion(req_version) { for (let i = 0; i < versions.length; i++) { if (semver.gt(versions[i], req_version)) { @@ -219,6 +231,8 @@ function sidebarVersion(req_version) { return null; } +// return whether or not the current sidebar.json file differs from the +// latest versioned one function diffLatestSidebar() { if (versions.length === 0) { return true; @@ -246,6 +260,7 @@ function diffLatestSidebar() { ); } +// return all versioned sidebar data function sidebarData() { const allSidebars = {}; diff --git a/lib/version.js b/lib/version.js index 54c8e91999..ebb48b1e40 100644 --- a/lib/version.js +++ b/lib/version.js @@ -59,6 +59,7 @@ if (ENABLE_TRANSLATION) { } mkdirp.sync(versionFolder); +// copy necessary files to new version, changing some of its metadata to reflect the versioning let files = glob.sync(CWD + "/../docs/*"); files.forEach(file => { const ext = path.extname(file); @@ -83,11 +84,13 @@ files.forEach(file => { let targetFile = CWD + "/versioned_docs/version-" + version + "/" + path.basename(file); if (ENABLE_TRANSLATION) { - targetFile = CWD + "/versioned_docs/en/version-" + version + "/" + path.basename(file); + targetFile = + CWD + "/versioned_docs/en/version-" + version + "/" + path.basename(file); } fs.writeFileSync(targetFile, makeHeader(metadata) + rawContent, "utf8"); }); +// copy sidebar if necessary if (versionFallback.diffLatestSidebar()) { mkdirp(CWD + "/versioned_sidebars"); const sidebar = JSON.parse(fs.readFileSync(CWD + "/sidebar.json", "utf8")); From 67592dcf8af0becbdd9ed081b289156bb9dea40a Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 3 Aug 2017 15:58:56 -0700 Subject: [PATCH 03/10] Use versions.json file and move versioned, translated docs into translated_docs --- lib/server/generate.js | 6 ++++-- lib/server/server.js | 4 ++-- lib/server/versionFallback.js | 19 +++---------------- lib/version.js | 26 ++++++++++++-------------- 4 files changed, 21 insertions(+), 34 deletions(-) diff --git a/lib/server/generate.js b/lib/server/generate.js index d7f05ad8b1..42b8882738 100644 --- a/lib/server/generate.js +++ b/lib/server/generate.js @@ -106,9 +106,9 @@ function execute() { let file; if (metadata.version) { - if (ENABLE_TRANSLATION) { + if (ENABLE_TRANSLATION && metadata.language !== "en") { file = - CWD + "/versioned_docs/" + metadata.language + "/" + metadata.source; + CWD + "/translated_docs/" + metadata.language + "/" + metadata.source; } else { file = CWD + "/versioned_docs/" + metadata.source; } @@ -120,9 +120,11 @@ function execute() { CWD + "/translated_docs/" + metadata.language + "/" + metadata.source; } } + if (!fs.existsSync(file)) { return; } + let rawContent = readMetadata.extractMetadata(fs.readFileSync(file, "utf8")) .rawContent; diff --git a/lib/server/server.js b/lib/server/server.js index e0fe145f15..9ea89fce3a 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -159,9 +159,9 @@ function execute(port) { let file; if (metadata.version) { - if (ENABLE_TRANSLATION) { + if (ENABLE_TRANSLATION && metadata.language !== "en") { file = - CWD + "/versioned_docs/" + metadata.language + "/" + metadata.source; + CWD + "/translated_docs/" + metadata.language + "/" + metadata.source; } else { file = CWD + "/versioned_docs/" + metadata.source; } diff --git a/lib/server/versionFallback.js b/lib/server/versionFallback.js index 4683ea7d48..a902590ac1 100644 --- a/lib/server/versionFallback.js +++ b/lib/server/versionFallback.js @@ -14,6 +14,8 @@ const fs = require("fs"); const path = require("path"); const diff = require("diff"); const assert = require("assert"); + +const versions = require(CWD + "/versions.json"); const siteConfig = require(CWD + "/siteConfig.js"); const ENABLE_TRANSLATION = fs.existsSync(CWD + "/languages.js"); @@ -68,20 +70,7 @@ function extractMetadata(content) { /*****************************************************************/ -// versions is an array of all versions currently in use -const versions = []; -const versionFolder = ENABLE_TRANSLATION - ? CWD + "/versioned_docs/en/" - : CWD + "/versioned_docs/"; -let files = glob.sync(versionFolder + "*"); -files.forEach(file => { - if (!fs.lstatSync(file).isDirectory()) { - return; - } - const version = file.split("version-")[1]; - versions.push(version); -}); -versions.sort(semver.rcompare); +const versionFolder = CWD + "/versioned_docs/"; // available stores doc ids of documents that are available for // each version @@ -184,8 +173,6 @@ function processVersionMetadata(file, version, useVersion, language) { // return all metadata of versioned documents function docData() { - const files = glob.sync(CWD + "/versioned_docs/**"); - allIds = new Set(); Object.keys(versionFiles).forEach(version => { Object.keys(versionFiles[version]).forEach(id => { diff --git a/lib/version.js b/lib/version.js index ebb48b1e40..16510edbee 100644 --- a/lib/version.js +++ b/lib/version.js @@ -9,16 +9,15 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -const CWD = process.cwd(); const glob = require("glob"); const fs = require("fs-extra"); const path = require("path"); const mkdirp = require("mkdirp"); -const semver = require("semver"); const readMetadata = require("./server/readMetadata.js"); const versionFallback = require("./server/versionFallback.js"); -const ENABLE_TRANSLATION = fs.existsSync(CWD + "/languages.js"); +const CWD = process.cwd(); +const versions = require(CWD + "/versions.json"); let version; @@ -37,9 +36,9 @@ if (typeof version === "undefined") { process.exit(1); } -if (!(version = semver.valid(version))) { +if (versions.includes(version)) { console.error( - "Invalid version!\nSpecify a valid version following the specifications at http://semver.org/." + "This verison already exists!\nSpecify a new version to create that does not already exist." ); process.exit(1); } @@ -53,10 +52,8 @@ function makeHeader(metadata) { return header; } -let versionFolder = CWD + "/versioned_docs/version-" + version; -if (ENABLE_TRANSLATION) { - versionFolder = CWD + "/versioned_docs/en/version-" + version; -} +const versionFolder = CWD + "/versioned_docs/version-" + version; + mkdirp.sync(versionFolder); // copy necessary files to new version, changing some of its metadata to reflect the versioning @@ -81,12 +78,9 @@ files.forEach(file => { metadata.original_id = metadata.id; metadata.id = "version-" + version + "-" + metadata.id; - let targetFile = + const targetFile = CWD + "/versioned_docs/version-" + version + "/" + path.basename(file); - if (ENABLE_TRANSLATION) { - targetFile = - CWD + "/versioned_docs/en/version-" + version + "/" + path.basename(file); - } + fs.writeFileSync(targetFile, makeHeader(metadata) + rawContent, "utf8"); }); @@ -117,3 +111,7 @@ if (versionFallback.diffLatestSidebar()) { "utf8" ); } + +// update versions.json file +versions.unshift(version); +fs.writeFileSync(CWD + "/versions.json", JSON.stringify(versions, null, 2)); From 1517b155b7a6d53d9726dadcc4518479436980eb Mon Sep 17 00:00:00 2001 From: Frank Li Date: Thu, 3 Aug 2017 16:00:17 -0700 Subject: [PATCH 04/10] Remove semver dependency --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 03a9ca9bc7..48f7ca938f 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,6 @@ "react": "^15.5.4", "react-dom": "^15.5.4", "request": "^2.81.0", - "semver": "^5.4.1", "shelljs": "^0.7.8" }, "name": "docusaurus", From 9eb6ff203486d9ef8c10d237afb105ce3e79211b Mon Sep 17 00:00:00 2001 From: Frank Li Date: Fri, 4 Aug 2017 10:44:54 -0700 Subject: [PATCH 05/10] Update write-translations.js to find versioned sidebar category names --- lib/write-translations.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/write-translations.js b/lib/write-translations.js index 24c46f1514..d8a0f4bc13 100644 --- a/lib/write-translations.js +++ b/lib/write-translations.js @@ -74,6 +74,20 @@ function execute() { }); }); + files = glob.sync(CWD + "/versioned_sidebars/*"); + files.forEach(file => { + if (!file.endsWith("-sidebar.json")) { + return; + } + sidebarContent = JSON.parse(fs.readFileSync(file, "utf8")); + Object.keys(sidebarContent).forEach(sb => { + const categories = sidebarContent[sb]; + Object.keys(categories).forEach(category => { + translations["localized-strings"][category] = category; + }); + }); + }); + /* go through pages to look for text inside translate tags */ files = glob.sync(CWD + "/pages/en/**"); files.forEach(file => { From 63043c041a0f19657637afd594358e569ed6eb90 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Fri, 4 Aug 2017 12:41:13 -0700 Subject: [PATCH 06/10] Add version header link and change current docs to be version 'next' --- lib/core/nav/HeaderNav.js | 24 ++++++++++++++++++++++-- lib/server/generate.js | 24 ++++++++++++++++++------ lib/server/readMetadata.js | 18 +++++++++++++++++- lib/server/server.js | 19 +++++++++++++++---- lib/server/versionFallback.js | 15 +++++++++++++-- lib/static/css/main.css | 7 +++++++ 6 files changed, 92 insertions(+), 15 deletions(-) diff --git a/lib/core/nav/HeaderNav.js b/lib/core/nav/HeaderNav.js index bf2b128486..1b6728e687 100644 --- a/lib/core/nav/HeaderNav.js +++ b/lib/core/nav/HeaderNav.js @@ -7,11 +7,20 @@ * of patent rights can be found in the PATENTS file in the same directory. */ -const React = require("react"); +const CWD = process.cwd(); -const siteConfig = require(process.cwd() + "/siteConfig.js"); +const React = require("react"); +const fs = require("fs"); +const siteConfig = require(CWD + "/siteConfig.js"); const translation = require("../../server/translation.js"); +const ENABLE_TRANSLATION = fs.existsSync(CWD + "/languages.js"); +const ENABLE_VERSIONING = fs.existsSync(CWD + "/versions.json"); +let versions; +if (ENABLE_VERSIONING) { + versions = require(CWD + "/versions.json"); +} + class LanguageDropDown extends React.Component { render() { const enabledLanguages = []; @@ -135,6 +144,11 @@ class HeaderNav extends React.Component { } render() { + const versionsLink = + this.props.baseUrl + + (ENABLE_TRANSLATION + ? this.props.language + "/versions.html" + : "versions.html"); return (
    diff --git a/lib/server/generate.js b/lib/server/generate.js index 42b8882738..4a0979f3d7 100644 --- a/lib/server/generate.js +++ b/lib/server/generate.js @@ -23,8 +23,10 @@ function execute() { const versionFallback = require("./versionFallback.js"); const ENABLE_TRANSLATION = fs.existsSync(CWD + "/languages.js"); + const ENABLE_VERSIONING = fs.existsSync(CWD + "/versions.json"); + let languages; - if (fs.existsSync(CWD + "/languages.js")) { + if (ENABLE_TRANSLATION) { languages = require(CWD + "/languages.js"); } else { languages = [ @@ -84,10 +86,11 @@ function execute() { const mdToHtml = {}; Object.keys(Metadata).forEach(id => { const metadata = Metadata[id]; - if (metadata.language !== "en" || metadata.version) { + if (metadata.language !== "en" || metadata.original_id) { return; } - let htmlLink = siteConfig.baseUrl + metadata.permalink; + let htmlLink = + siteConfig.baseUrl + metadata.permalink.replace("/next/", "/"); if (htmlLink.includes("/docs/en/")) { htmlLink = htmlLink.replace("/docs/en/", "/docs/en/VERSION/"); } else { @@ -105,7 +108,7 @@ function execute() { const metadata = Metadata[id]; let file; - if (metadata.version) { + if (metadata.original_id) { if (ENABLE_TRANSLATION && metadata.language !== "en") { file = CWD + "/translated_docs/" + metadata.language + "/" + metadata.source; @@ -124,7 +127,7 @@ function execute() { if (!fs.existsSync(file)) { return; } - + let rawContent = readMetadata.extractMetadata(fs.readFileSync(file, "utf8")) .rawContent; @@ -135,13 +138,22 @@ function execute() { rawContent = insertTableOfContents(rawContent); } + let latestVersion; + if (ENABLE_VERSIONING) { + latestVersion = JSON.parse( + fs.readFileSync(CWD + "/versions.json", "utf8") + )[0]; + } + /* replace any links to markdown files to their website html links */ Object.keys(mdToHtml).forEach(function(key, index) { let link = mdToHtml[key]; link = link.replace("/en/", "/" + language + "/"); link = link.replace( "/VERSION/", - metadata.version ? "/" + metadata.version + "/" : "/" + metadata.version && (metadata.version !== latestVersion) + ? "/" + metadata.version + "/" + : "/" ); rawContent = rawContent.replace(new RegExp(key, "g"), link); }); diff --git a/lib/server/readMetadata.js b/lib/server/readMetadata.js index 7b7f4614b0..4c816034eb 100644 --- a/lib/server/readMetadata.js +++ b/lib/server/readMetadata.js @@ -14,7 +14,10 @@ const fs = require("fs"); const os = require("os"); const glob = require("glob"); const siteConfig = require(CWD + "/siteConfig.js"); -const versionFallback = require("./versionFallback"); +const versionFallback = require("./versionFallback.js"); + +const ENABLE_VERSIONING = fs.existsSync(CWD + "/versions.json"); + let languages; if (fs.existsSync(CWD + "/languages.js")) { languages = require(CWD + "/languages.js"); @@ -94,6 +97,7 @@ function extractMetadata(content) { return { metadata, rawContent: both.content }; } +// process the metadata for a document found in the docs folder function processMetadata(file) { const result = extractMetadata(fs.readFileSync(file, "utf8")); if (!result.metadata || !result.rawContent) { @@ -118,6 +122,18 @@ function processMetadata(file) { metadata.permalink = "docs/" + language + "/" + metadata.id + ".html"; } + if (ENABLE_VERSIONING) { + metadata.version = "next"; + if (languages.length === 1 && !siteConfig.useEnglishUrl) { + metadata.permalink = metadata.permalink.replace("docs/", "docs/next/"); + } else { + metadata.permalink = metadata.permalink.replace( + "docs/" + language + "/", + "docs/" + language + "/next/" + ); + } + } + // change ids previous, next metadata.localized_id = metadata.id; metadata.id = language + "-" + metadata.id; diff --git a/lib/server/server.js b/lib/server/server.js index 9ea89fce3a..af810e7af5 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -24,6 +24,7 @@ function execute(port) { const CWD = process.cwd(); const ENABLE_TRANSLATION = fs.existsSync(CWD + "/languages.js"); + const ENABLE_VERSIONING = fs.existsSync(CWD + "/versions.json"); let siteConfig = require(CWD + "/siteConfig.js"); @@ -142,10 +143,11 @@ function execute(port) { const mdToHtml = {}; Object.keys(Metadata).forEach(id => { const metadata = Metadata[id]; - if (metadata.language !== "en" || metadata.version) { + if (metadata.language !== "en" || metadata.original_id) { return; } - let htmlLink = siteConfig.baseUrl + metadata.permalink; + let htmlLink = + siteConfig.baseUrl + metadata.permalink.replace("/next/", "/"); if (htmlLink.includes("/docs/en/")) { htmlLink = htmlLink.replace("/docs/en/", "/docs/en/VERSION/"); } else { @@ -158,7 +160,7 @@ function execute(port) { const language = metadata.language; let file; - if (metadata.version) { + if (metadata.original_id) { if (ENABLE_TRANSLATION && metadata.language !== "en") { file = CWD + "/translated_docs/" + metadata.language + "/" + metadata.source; @@ -187,13 +189,22 @@ function execute(port) { rawContent = insertTableOfContents(rawContent); } + let latestVersion; + if (ENABLE_VERSIONING) { + latestVersion = JSON.parse( + fs.readFileSync(CWD + "/versions.json", "utf8") + )[0]; + } + /* replace any links to markdown files to their website html links */ Object.keys(mdToHtml).forEach(function(key, index) { let link = mdToHtml[key]; link = link.replace("/en/", "/" + language + "/"); link = link.replace( "/VERSION/", - metadata.version ? "/" + metadata.version + "/" : "/" + metadata.version && (metadata.version !== latestVersion) + ? "/" + metadata.version + "/" + : "/" ); rawContent = rawContent.replace(new RegExp(key, "g"), link); }); diff --git a/lib/server/versionFallback.js b/lib/server/versionFallback.js index a902590ac1..5d1de3253d 100644 --- a/lib/server/versionFallback.js +++ b/lib/server/versionFallback.js @@ -152,12 +152,23 @@ function diffLatestDoc(file, id) { function processVersionMetadata(file, version, useVersion, language) { const metadata = extractMetadata(fs.readFileSync(file, "utf8")).metadata; metadata.source = "version-" + useVersion + "/" + path.basename(file); + + const latestVersion = versions[0]; + if (!ENABLE_TRANSLATION && !siteConfig.useEnglishUrl) { metadata.permalink = - "docs/" + version + "/" + metadata.original_id + ".html"; + "docs/" + + (version !== latestVersion ? version + "/" : "") + + metadata.original_id + + ".html"; } else { metadata.permalink = - "docs/" + language + "/" + version + "/" + metadata.original_id + ".html"; + "docs/" + + language + + "/" + + (version !== latestVersion ? version + "/" : "") + + metadata.original_id + + ".html"; } metadata.id = metadata.id.replace( "version-" + useVersion + "-", diff --git a/lib/static/css/main.css b/lib/static/css/main.css index 06484bf7d2..2ad07d6d2a 100644 --- a/lib/static/css/main.css +++ b/lib/static/css/main.css @@ -512,6 +512,13 @@ header h2 { position: relative; z-index: 9999; } +.fixedHeaderContainer header h3 { + text-decoration: underline; + font-family: "Helvetica Neue", Arial, sans-serif; + color: white; + margin-left: 10px; + font-size: 16px; +} .promoSection { display: flex; From 5c3f74ddcc6db5673a34b19995ca751b3b2bb4d7 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Fri, 4 Aug 2017 12:57:43 -0700 Subject: [PATCH 07/10] Fix removal of semver usage --- lib/server/versionFallback.js | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/server/versionFallback.js b/lib/server/versionFallback.js index 5d1de3253d..8cdbdd4636 100644 --- a/lib/server/versionFallback.js +++ b/lib/server/versionFallback.js @@ -8,7 +8,6 @@ */ const CWD = process.cwd(); -const semver = require("semver"); const glob = require("glob"); const fs = require("fs"); const path = require("path"); @@ -102,8 +101,14 @@ files.forEach(file => { // returns the version to use for a document based on its id and // what the requested version is function docVersion(id, req_version) { + // iterate through versions until a version less than or equal to the requested + // is found, then check if that verison has an available file to use + let requestedFound = false; for (let i = 0; i < versions.length; i++) { - if (semver.gt(versions[i], req_version)) { + if (versions[i] === req_version) { + requestedFound = true; + } + if (!requestedFound) { continue; } if (!available[id]) { @@ -214,8 +219,14 @@ function docData() { // return the version of the sidebar to use given a requested version function sidebarVersion(req_version) { + // iterate through versions until a version less than or equal to the requested + // is found, then check if that verison has an available file to use + let requestedFound = false; for (let i = 0; i < versions.length; i++) { - if (semver.gt(versions[i], req_version)) { + if (versions[i] === req_version) { + requestedFound = true; + } + if (!requestedFound) { continue; } if ( From de2897f108c028cc050be0fb70ba293452504f0d Mon Sep 17 00:00:00 2001 From: Frank Li Date: Fri, 4 Aug 2017 14:44:23 -0700 Subject: [PATCH 08/10] Allow for extra algoliaOptions for search --- lib/core/Site.js | 53 +++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/lib/core/Site.js b/lib/core/Site.js index f499bb3934..7013d62da3 100644 --- a/lib/core/Site.js +++ b/lib/core/Site.js @@ -8,40 +8,25 @@ */ const React = require("react"); +const fs = require("fs"); const HeaderNav = require("./nav/HeaderNav.js"); const Head = require("./Head.js"); const Footer = require(process.cwd() + "/core/Footer.js"); const translation = require("../server/translation.js"); +const CWD = process.cwd(); + class Site extends React.Component { /* goes in body after navPusher -
    -