const fs = require('fs-extra'); const dirname = require('path').dirname; const Mustache = require('mustache'); const headerHtml = ` {{pageTitle}}

Joplin

An open source note taking and to-do application with synchronisation capabilities

{{{tocHtml}}} `; const footerHtml = ` `; // const screenshotHtml = ` // // // // // // // // // //
// Mobile // // Command line //
// // //
// joplin:/My notebook$ ls -n 12
// [ ] 8am conference call ☎
// [ ] Make vet appointment
// [ ] Go pick up parcel
// [ ] Pay flat rent 💸
// [X] Book ferry 🚢
// [X] Deploy Joplin app
//     Open source stuff
//     Swimming pool time table 🏊
//     Grocery shopping list 📝
//     Work itinerary
//     Tuesday random note
//     Vacation plans ☀
// 			
//
// `; const scriptHtml = ` `; const rootDir = dirname(__dirname); function markdownToHtml(md, templateParams) { const MarkdownIt = require('markdown-it'); const markdownIt = new MarkdownIt({ breaks: true, linkify: true, html: true, }); markdownIt.core.ruler.push('checkbox', state => { const tokens = state.tokens; const Token = state.Token; const doneNames = []; const headingTextToAnchorName = (text, doneNames) => { const allowed = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; let lastWasDash = true; let output = ''; for (let i = 0; i < text.length; i++) { const c = text[i]; if (allowed.indexOf(c) < 0) { if (lastWasDash) continue; lastWasDash = true; output += '-'; } else { lastWasDash = false; output += c; } } output = output.toLowerCase(); while (output.length && output[output.length - 1] === '-') { output = output.substr(0, output.length - 1); } let temp = output; let index = 1; while (doneNames.indexOf(temp) >= 0) { temp = `${output}-${index}`; index++; } output = temp; return output; }; const createAnchorTokens = anchorName => { const output = []; { const token = new Token('heading_anchor_open', 'a', 1); token.attrs = [ ['name', anchorName], ['href', `#${anchorName}`], ['class', 'heading-anchor'], ]; output.push(token); } { const token = new Token('text', '', 0); token.content = '🔗'; output.push(token); } { const token = new Token('heading_anchor_close', 'a', -1); output.push(token); } return output; }; let insideHeading = false; for (let i = 0; i < tokens.length; i++) { const token = tokens[i]; if (token.type === 'heading_open') { insideHeading = true; continue; } if (token.type === 'heading_close') { insideHeading = false; continue; } if (insideHeading && token.type === 'inline') { const anchorName = headingTextToAnchorName(token.content, doneNames); doneNames.push(anchorName); const anchorTokens = createAnchorTokens(anchorName); // token.children = anchorTokens.concat(token.children); token.children = token.children.concat(anchorTokens); } } }); const improveDocHtml = ` `; return Mustache.render(headerHtml, templateParams) + markdownIt.render(md) + Mustache.render(improveDocHtml, templateParams) + scriptHtml + footerHtml; } let tocMd_ = null; let tocHtml_ = null; const tocRegex_ = /([^]*)/; function tocMd() { if (tocMd_) return tocMd_; const md = fs.readFileSync(`${rootDir}/README.md`, 'utf8'); const toc = md.match(tocRegex_); tocMd_ = toc[1]; return tocMd_; } function replaceGitHubByJoplinAppLinks(md) { return md.replace(/https:\/\/github.com\/laurent22\/joplin\/blob\/master\/readme\/(.*)\.md(#[^\s)]+|)/g, 'https://joplinapp.org/$1/$2'); } function tocHtml() { if (tocHtml_) return tocHtml_; const MarkdownIt = require('markdown-it'); const markdownIt = new MarkdownIt(); let md = tocMd(); md = md.replace(/# Table of contents/, ''); md = replaceGitHubByJoplinAppLinks(md); tocHtml_ = markdownIt.render(md); tocHtml_ = `
${tocHtml_}
`; return tocHtml_; } function renderMdToHtml(md, targetPath, templateParams) { // Remove the header because it's going to be added back as HTML md = md.replace(/# Joplin\n/, ''); templateParams.baseUrl = 'https://joplinapp.org'; templateParams.imageBaseUrl = `${templateParams.baseUrl}/images`; templateParams.tocHtml = tocHtml(); const title = []; if (!templateParams.title) { title.push('Joplin - an open source note taking and to-do application with synchronisation capabilities'); } else { title.push(templateParams.title); title.push('Joplin'); } md = replaceGitHubByJoplinAppLinks(md); templateParams.pageTitle = title.join(' | '); const html = markdownToHtml(md, templateParams); fs.writeFileSync(targetPath, html); } function renderFileToHtml(sourcePath, targetPath, templateParams) { const md = fs.readFileSync(sourcePath, 'utf8'); return renderMdToHtml(md, targetPath, templateParams); } function makeHomePageMd() { let md = fs.readFileSync(`${rootDir}/README.md`, 'utf8'); md = md.replace(tocRegex_, ''); // HACK: GitHub needs the \| or the inline code won't be displayed correctly inside the table, // while MarkdownIt doesn't and will in fact display the \. So we remove it here. md = md.replace(/\\\| bash/g, '| bash'); return md; } async function main() { tocMd(); renderMdToHtml(makeHomePageMd(), `${rootDir}/docs/index.html`, {}); const sources = [ [ 'readme/changelog.md', 'docs/changelog/index.html', { title: 'Changelog (Desktop App)' } ], [ 'readme/changelog_cli.md', 'docs/changelog_cli/index.html', { title: 'Changelog (CLI App)' } ], [ 'readme/clipper.md', 'docs/clipper/index.html', { title: 'Web Clipper' } ], [ 'readme/debugging.md', 'docs/debugging/index.html', { title: 'Debugging' } ], [ 'readme/desktop.md', 'docs/desktop/index.html', { title: 'Desktop Application' } ], [ 'readme/donate.md', 'docs/donate/index.html', { title: 'Donate' } ], [ 'readme/e2ee.md', 'docs/e2ee/index.html', { title: 'End-To-End Encryption' } ], [ 'readme/faq.md', 'docs/faq/index.html', { title: 'FAQ' } ], [ 'readme/mobile.md', 'docs/mobile/index.html', { title: 'Mobile Application' } ], [ 'readme/spec.md', 'docs/spec/index.html', { title: 'Specifications' } ], [ 'readme/stats.md', 'docs/stats/index.html', { title: 'Statistics' } ], [ 'readme/terminal.md', 'docs/terminal/index.html', { title: 'Terminal Application' } ], [ 'readme/api.md', 'docs/api/index.html', { title: 'REST API' } ], [ 'readme/prereleases.md', 'docs/prereleases/index.html', { title: 'Pre-releases' } ], [ 'readme/markdown.md', 'docs/markdown/index.html', { title: 'Markdown Guide' } ], [ 'readme/nextcloud_app.md', 'docs/nextcloud_app/index.html', { title: 'Joplin Web API for Nextcloud' } ], [ 'readme/gsoc/index.md', 'docs/gsoc/index.html', { title: 'Google Summer of Code' } ], [ 'readme/gsoc/idea_nextcloud.md', 'docs/gsoc/idea_nextcloud.html', { title: 'GSoC: Idea: Nextcloud' } ], [ 'readme/gsoc/idea_collaboration.md', 'docs/gsoc/idea_collaboration.html', { title: 'GSoC: Idea: Collaboration' } ], [ 'readme/gsoc/idea_hierarchical_tags.md', 'docs/gsoc/idea_hierarchical_tags.html', { title: 'GSoC: Idea: Hiearchical Tags' } ], [ 'readme/gsoc/idea_search.md', 'docs/gsoc/idea_search.html', { title: 'GSoC: Idea: Search' } ], [ 'readme/gsoc/idea_mobile_sharing.md', 'docs/gsoc/idea_mobile_sharing.html', { title: 'GSoC: Idea: Mobile Sharing' } ], [ 'readme/gsoc/idea_ocr.md', 'docs/gsoc/idea_ocr.html', { title: 'GSoC: Idea: OCR Support' } ], [ 'readme/gsoc/idea_multi_profiles.md', 'docs/gsoc/idea_multi_profiles.html', { title: 'GSoC: Idea: Multi-Profile Support' } ], ]; const path = require('path'); for (const source of sources) { source[2].sourceMarkdownFile = source[0]; source[2].sourceMarkdownName = path.basename(source[0], path.extname(source[0])); renderFileToHtml(`${rootDir}/${source[0]}`, `${rootDir}/${source[1]}`, source[2]); } } main().catch((error) => { console.error(error); });