/** * 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 CWD = process.cwd(); const path = require("path"); const fs = require("fs"); const glob = require("glob"); const chalk = require("chalk"); const siteConfig = require(CWD + "/siteConfig.js"); 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"); } else { languages = [ { enabled: true, name: "English", tag: "en" } ]; } // returns map from id to object containing sidebar ordering info function readSidebar() { let allSidebars; if (fs.existsSync(CWD + "/sidebars.json")) { allSidebars = require(CWD + "/sidebars.json"); } else { allSidebars = {}; } Object.assign(allSidebars, versionFallback.sidebarData()); const order = {}; Object.keys(allSidebars).forEach(sidebar => { const categories = allSidebars[sidebar]; let ids = []; let categoryOrder = []; Object.keys(categories).forEach(category => { ids = ids.concat(categories[category]); for (let i = 0; i < categories[category].length; i++) { categoryOrder.push(category); } }); for (let i = 0; i < ids.length; i++) { const id = ids[i]; let previous, next; if (i > 0) previous = ids[i - 1]; if (i < ids.length - 1) next = ids[i + 1]; order[id] = { previous: previous, next: next, sidebar: sidebar, category: categoryOrder[i] }; } }); return order; } // split markdown header 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); // if no content returned, then that means there was no header, and both.header is the content if (!both.content) { return {metadata, rawContent: both.header}; } 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(); try { value = JSON.parse(value); } catch (e) {} metadata[key] = value; } 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")); const regexSubFolder = /docs\/(.*)\/.*/; let language = "en"; const match = regexSubFolder.exec(file); if (match) { language = match[1]; } const metadata = result.metadata; const rawContent = result.rawContent; metadata.source = path.basename(file); if (!metadata.id) { metadata.id = path.basename(file, path.extname(file)); } if (metadata.id.includes("/")) { throw new Error('Document id cannot include "/".'); } if (!metadata.title) { metadata.title = metadata.id; } if (languages.length === 1 && !siteConfig.useEnglishUrl) { metadata.permalink = "docs/" + metadata.id + ".html"; } else { 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; metadata.language = language; const order = readSidebar(); const id = metadata.localized_id; if (order[id]) { metadata.sidebar = order[id].sidebar; metadata.category = order[id].category; if (order[id].next) { metadata.next_id = order[id].next; metadata.next = language + "-" + order[id].next; } if (order[id].previous) { metadata.previous_id = order[id].previous; metadata.previous = language + "-" + order[id].previous; } } return {metadata, rawContent: rawContent}; } // process metadata for all docs and save into core/metadata.js function generateDocsMetadata() { const order = readSidebar(); const regexSubFolder = /translated_docs\/(.*)\/.*/; const enabledLanguages = []; languages.filter(lang => lang.enabled).map(lang => { enabledLanguages.push(lang.tag); }); const metadatas = {}; // metadata for english files let files = glob.sync(CWD + "/../docs/**"); files.forEach(file => { let language = "en"; const extension = path.extname(file); if (extension === ".md" || extension === ".markdown") { const res = processMetadata(file); if (!res) { return; } let metadata = res.metadata; metadatas[metadata.id] = metadata; } }); // metadata for non-english docs files = glob.sync(CWD + "/translated_docs/**"); files.forEach(file => { let language = "en"; const match = regexSubFolder.exec(file); if (match) { language = match[1]; } if (enabledLanguages.indexOf(language) === -1) { return; } const extension = path.extname(file); if (extension === ".md" || extension === ".markdown") { const res = processMetadata(file); if (!res) { return; } let metadata = res.metadata; metadatas[metadata.id] = metadata; } }); // metadata for versioned docs const versionData = versionFallback.docData(); versionData.forEach(metadata => { const id = metadata.localized_id; if (order[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" + " * @generated\n" + " */\n" + "module.exports = " + JSON.stringify(metadatas, null, 2) + ";" ); } // process metadata for blog posts and save into core/MetadataBlog.js function generateBlogMetadata() { const metadatas = []; let files = glob.sync(CWD + "/blog/**/*.*"); if (!files || files.length == 0) { console.error( `${chalk.yellow( CWD + "/blog/ appears to be empty" )} Make sure you've put your blog files in your Docusaurus 'website' folder.` ); } files.sort().reverse().forEach(file => { const extension = path.extname(file); if (extension !== ".md" && extension !== ".markdown") { return; } // Transform // 2015-08-13-blog-post-name-0.5.md // into // 2015/08/13/blog-post-name-0-5.html const filePath = path .basename(file) .replace("-", "/") .replace("-", "/") .replace("-", "/") .replace(/\./g, "-") .replace(/\-md$/, ".html"); const result = extractMetadata(fs.readFileSync(file, {encoding: "utf8"})); const rawContent = result.rawContent; const metadata = Object.assign( {path: filePath, content: rawContent}, result.metadata ); metadata.id = metadata.title; // Extract, YYYY, MM, DD from the file name let filePathDateArr = path.basename(file).toString().split("-"); metadata.date = new Date( filePathDateArr[0] + "-" + filePathDateArr[1] + "-" + filePathDateArr[2] + "T06:00:00.000Z" ); metadatas.push(metadata); }); fs.writeFileSync( __dirname + "/../core/MetadataBlog.js", "/**\n" + " * @generated\n" + " */\n" + "module.exports = " + JSON.stringify(metadatas, null, 2) + ";" ); } module.exports = { readSidebar, extractMetadata, processMetadata, generateDocsMetadata, generateBlogMetadata };