/** * 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. */ function execute() { const CWD = process.cwd(); const fs = require("fs-extra"); const readMetadata = require("./readMetadata.js"); const renderToStaticMarkup = require("react-dom/server").renderToStaticMarkup; const path = require("path"); const toSlug = require("../core/toSlug.js"); const React = require("react"); const mkdirp = require("mkdirp"); const glob = require("glob"); const chalk = require("chalk"); 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"); const ENABLE_VERSIONING = fs.existsSync(CWD + "/versions.json"); let languages; if (ENABLE_TRANSLATION) { languages = require(CWD + "/languages.js"); } else { languages = [ { enabled: true, name: "English", tag: "en" } ]; } function writeFileAndCreateFolder(file, content) { mkdirp.sync(file.replace(new RegExp("/[^/]*$"), "")); fs.writeFileSync(file, content); } const TABLE_OF_CONTENTS_TOKEN = ""; const insertTableOfContents = rawContent => { const regexp = /\n###\s+(`.*`.*)\n/g; let match; const headers = []; while ((match = regexp.exec(rawContent))) { headers.push(match[1]); } const tableOfContents = headers .map(header => ` - [${header}](#${toSlug(header)})`) .join("\n"); return rawContent.replace(TABLE_OF_CONTENTS_TOKEN, tableOfContents); }; function isSeparateCss(file) { if (!siteConfig.separateCss) { return false; } for (let i = 0; i < siteConfig.separateCss.length; i++) { if (file.includes(siteConfig.separateCss[i])) { return true; } } return false; } console.log("generate.js triggered..."); const enabledLanguages = []; languages.filter(lang => lang.enabled).map(lang => { enabledLanguages.push(lang.tag); }); readMetadata.generateDocsMetadata(); const Metadata = require("../core/metadata.js"); const mdToHtml = {}; Object.keys(Metadata).forEach(id => { const metadata = Metadata[id]; if (metadata.language !== "en" || metadata.original_id) { return; } let htmlLink = siteConfig.baseUrl + metadata.permalink.replace("/next/", "/"); if (htmlLink.includes("/docs/en/")) { htmlLink = htmlLink.replace("/docs/en/", "/docs/en/VERSION/"); } else { htmlLink = htmlLink.replace("/docs/", "/docs/VERSION/"); } mdToHtml[metadata.source] = htmlLink; }); const DocsLayout = require("../core/DocsLayout.js"); fs.removeSync(CWD + "/build"); // create html files for all docs Object.keys(Metadata).forEach(id => { const metadata = Metadata[id]; let file; if (metadata.original_id) { if (ENABLE_TRANSLATION && metadata.language !== "en") { file = CWD + "/translated_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; } } if (!fs.existsSync(file)) { return; } let rawContent = readMetadata.extractMetadata(fs.readFileSync(file, "utf8")) .rawContent; const language = metadata.language; /* generate table of contents if appropriate */ if (rawContent && rawContent.indexOf(TABLE_OF_CONTENTS_TOKEN) != -1) { 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 !== latestVersion ? "/" + metadata.version + "/" : "/" ); 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")) { fs.copySync( CWD + "/../docs/assets", CWD + "/build/" + siteConfig.projectName + "/docs/assets" ); } // create html files for all blog posts if (fs.existsSync(__dirname + "../core/MetadataBlog.js")) { fs.removeSync(__dirname + "../core/MetadataBlog.js"); } readMetadata.generateBlogMetadata(); const MetadataBlog = require("../core/MetadataBlog.js"); const BlogPostLayout = require("../core/BlogPostLayout.js"); let files = glob.sync(CWD + "/blog/**/*.*"); files.sort().reverse().forEach(file => { const extension = path.extname(file); if (extension !== ".md" && extension !== ".markdown") { return; } /* convert filename ot use slashes */ const filePath = path .basename(file) .replace("-", "/") .replace("-", "/") .replace("-", "/") .replace(/\./g, "-") .replace(/\-md$/, ".html"); const result = readMetadata.extractMetadata( fs.readFileSync(file, { encoding: "utf8" }) ); const rawContent = result.rawContent; const metadata = Object.assign( { path: filePath, content: rawContent }, result.metadata ); metadata.id = metadata.title; let language = "en"; const blogPostComp = ( {rawContent} ); const str = renderToStaticMarkup(blogPostComp); let targetFile = CWD + "/build/" + siteConfig.projectName + "/blog/" + filePath; writeFileAndCreateFolder(targetFile, str); }); // create html files for all blog pages const BlogPageLayout = require("../core/BlogPageLayout.js"); const perPage = 10; for (let page = 0; page < Math.ceil(MetadataBlog.length / perPage); page++) { let language = "en"; const metadata = { page: page, perPage: perPage }; const blogPageComp = ( ); const str = renderToStaticMarkup(blogPageComp); let targetFile = CWD + "/build/" + siteConfig.projectName + "/blog" + (page > 0 ? "/page" + (page + 1) : "") + "/index.html"; writeFileAndCreateFolder(targetFile, str); } /* copy blog assets if they exist */ if (fs.existsSync(CWD + "/blog/assets")) { fs.copySync( CWD + "/blog/assets", CWD + "/build/" + siteConfig.projectName + "/blog/assets" ); } /* copy all static files from docusaurus */ files = glob.sync(__dirname + "/../static/**"); files.forEach(file => { let targetFile = CWD + "/build/" + siteConfig.projectName + "/" + file.split("/static/")[1]; if (file.match(/\.css$/)) { let cssContent = fs.readFileSync(file, "utf8"); if ( !siteConfig.colors.primaryColor || !siteConfig.colors.secondaryColor || !siteConfig.colors.prismColor ) { console.error( `${chalk.yellow( "Missing color configuration." )} Make sure siteConfig.colors includes primaryColor, secondaryColor, and prismColor fields.` ); } Object.keys(siteConfig.colors).forEach(key => { const color = siteConfig.colors[key]; cssContent = cssContent.replace(new RegExp("\\$" + key, "g"), color); }); mkdirp.sync(targetFile.replace(new RegExp("/[^/]*$"), "")); fs.writeFileSync(targetFile, cssContent); } else if (!fs.lstatSync(file).isDirectory()) { mkdirp.sync(targetFile.replace(new RegExp("/[^/]*$"), "")); fs.copySync(file, targetFile); } }); /* copy all static files from user */ files = glob.sync(CWD + "/static/**"); files.forEach(file => { if (file.match(/\.css$/) && !isSeparateCss(file)) { const mainCss = CWD + "/build/" + siteConfig.projectName + "/css/main.css"; let cssContent = fs.readFileSync(file, "utf8"); cssContent = fs.readFileSync(mainCss, "utf8") + "\n" + cssContent; Object.keys(siteConfig.colors).forEach(key => { const color = siteConfig.colors[key]; cssContent = cssContent.replace(new RegExp("\\$" + key, "g"), color); }); fs.writeFileSync(mainCss, cssContent); } else if (!fs.lstatSync(file).isDirectory()) { let parts = file.split("static"); let targetFile = CWD + "/build/" + siteConfig.projectName + "/" + parts[1]; mkdirp.sync(targetFile.replace(new RegExp("/[^/]*$"), "")); fs.copySync(file, targetFile); } }); /* compile/copy pages from user */ files = glob.sync(CWD + "/pages/**"); files.forEach(file => { if (file.match(/\.js$/)) { /* make temp file for sake of require paths */ const parts = file.split("pages"); let tempFile = __dirname + "/../pages" + parts[1]; tempFile = tempFile.replace( path.basename(file), "temp" + path.basename(file) ); mkdirp.sync(tempFile.replace(new RegExp("/[^/]*$"), "")); fs.copySync(file, tempFile); const ReactComp = require(tempFile); let targetFile = CWD + "/build/" + siteConfig.projectName + "/" + parts[1]; targetFile = targetFile.replace(/\.js$/, ".html"); const regexLang = /\/pages\/(.*)\//; const match = regexLang.exec(file); const langParts = match[1].split("/"); if (langParts.indexOf("en") !== -1) { /* copy and compile a page for each enabled language from the English file */ for (let i = 0; i < enabledLanguages.length; i++) { let language = enabledLanguages[i]; /* skip conversion from english file if a file exists for this language */ if ( language !== "en" && fs.existsSync(file.replace("/en/", "/" + language + "/")) ) { continue; } translate.setLanguage(language); const str = renderToStaticMarkup( ); writeFileAndCreateFolder( targetFile.replace("/en/", "/" + language + "/"), str ); } } else { /* allow for rendering of other files not in pages/en folder */ let language = "en"; for (let i = 0; i < langParts.length; i++) { if (enabledLanguages.indexOf(langParts[i]) !== -1) { language = langParts[i]; } } translate.setLanguage(language); const str = renderToStaticMarkup( ); writeFileAndCreateFolder(targetFile, str); } fs.removeSync(tempFile); } else if (!fs.lstatSync(file).isDirectory()) { let parts = file.split("pages"); let targetFile = CWD + "/build/" + siteConfig.projectName + "/" + parts[1]; mkdirp.sync(targetFile.replace(new RegExp("/[^/]*$"), "")); fs.copySync(file, targetFile); } }); /* copy html files in 'en' to base level as well */ files = glob.sync(CWD + "/build/" + siteConfig.projectName + "/en/**"); files.forEach(file => { let targetFile = file.replace("en/", ""); if (file.match(/\.html$/)) { fs.copySync(file, targetFile); } }); /* Generate CNAME file if a custom domain is specified in siteConfig */ if (siteConfig.cname) { let targetFile = CWD + "/build/" + siteConfig.projectName + "/CNAME"; fs.writeFileSync(targetFile, siteConfig.cname); } } module.exports = execute;