const sanitizeHtml = require('sanitize-html'); const fs = require("fs"); const path = require("path"); const html = require("html"); const TMP_API_DOCS = './tmp/api_docs'; const TMP_FE_DOCS = TMP_API_DOCS + '/frontend_api'; const TMP_BE_DOCS = TMP_API_DOCS + '/backend_api'; const sourceFiles = getFilesRecursively(TMP_API_DOCS); for (const sourcePath of sourceFiles) { const content = fs.readFileSync(sourcePath).toString(); const transformedContent = transform(content); const prettifiedContent = html.prettyPrint(transformedContent, {indent_size: 2}); const filteredContent = prettifiedContent .replace(/
Documentation generated by [^<]+<\/a>/gi, '') .replace(/JSDoc: (Class|Module): [a-z]+/gi, ''); const destPath = sourcePath.replaceAll("tmp", "docs"); fs.mkdirSync(path.dirname(destPath), {recursive: true}); fs.writeFileSync(destPath, filteredContent.trim()); console.log(destPath); } const USER_GUIDE_DIR = './docs/user_guide'; const META_PATH = USER_GUIDE_DIR + '/!!!meta.json'; const meta = JSON.parse(fs.readFileSync(META_PATH).toString()); const rootNoteMeta = meta.files[0]; const {noteMeta: scriptApiDocsRoot, filePath: scriptApiDocsRootFilePath, notePath: scriptApiDocsRootNotePath} = findNoteMeta(rootNoteMeta, 'Script API', []); const BE_FILES = ['AbstractBeccaEntity', 'BAttribute', 'BBranch', 'BEtapiToken', 'BNote', 'BNoteRevision', 'BOption', 'BRecentNote', 'module-sql']; const FE_FILES = ['FNote', 'FAttribute', 'FBranch', 'FNoteComplement']; scriptApiDocsRoot.dirFileName = scriptApiDocsRoot.dataFileName.substr(0, scriptApiDocsRoot.dataFileName.length - 5); scriptApiDocsRoot.children = getScriptApiMeta(); fs.writeFileSync(META_PATH, JSON.stringify(meta, null, 2)); const scriptApiDocsRootDir = USER_GUIDE_DIR + scriptApiDocsRootFilePath; fs.mkdirSync(scriptApiDocsRootDir, {recursive: true}); fs.mkdirSync(scriptApiDocsRootDir + '/BackendScriptApi', {recursive: true}); fs.mkdirSync(scriptApiDocsRootDir + '/FrontendScriptApi', {recursive: true}); const BE_ROOT = scriptApiDocsRootDir + '/BackendScriptApi.html'; const FE_ROOT = scriptApiDocsRootDir + '/FrontendScriptApi.html'; fs.copyFileSync(TMP_BE_DOCS + '/BackendScriptApi.html', BE_ROOT); fs.copyFileSync(TMP_FE_DOCS + '/FrontendScriptApi.html', FE_ROOT); for (const file of BE_FILES) { fs.copyFileSync(TMP_BE_DOCS + '/' + file + '.html', `${scriptApiDocsRootDir}/BackendScriptApi/${file}.html`); } rewriteLinks(BE_ROOT, BE_FILES, 'BackendScriptApi'); for (const file of FE_FILES) { fs.copyFileSync(TMP_FE_DOCS + '/' + file + '.html', `${scriptApiDocsRootDir}/FrontendScriptApi/${file}.html`); } rewriteLinks(FE_ROOT, FE_FILES, 'FrontendScriptApi'); fs.rmSync(USER_GUIDE_DIR + '/index.html', {force: true}); fs.rmSync(USER_GUIDE_DIR + '/navigation.html', {force: true}); fs.rmSync(USER_GUIDE_DIR + '/style.css', {force: true}); function getFilesRecursively(directory) { const files = []; function getFilesRecursivelyInner(directory) { const filesInDirectory = fs.readdirSync(directory); for (const file of filesInDirectory) { const absolute = path.join(directory, file); if (fs.statSync(absolute).isDirectory()) { getFilesRecursivelyInner(absolute); } else if (file.endsWith('.html')) { files.push(absolute); } } } getFilesRecursivelyInner(directory); return files; } function transform(content) { const result = sanitizeHtml(content, { allowedTags: [ 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol', 'li', 'b', 'i', 'strong', 'em', 'strike', 's', 'del', 'abbr', 'code', 'hr', 'br', 'div', 'table', 'thead', 'caption', 'tbody', 'tr', 'th', 'td', 'pre', 'section', 'img', 'figure', 'figcaption', 'span', 'label', 'input', ], nonTextTags: [ 'style', 'script', 'textarea', 'option', 'h1', 'h2', 'h3', 'nav' ], allowedAttributes: { 'a': [ 'href', 'class', 'data-note-path' ], 'img': [ 'src' ], 'section': [ 'class', 'data-note-id' ], 'figure': [ 'class' ], 'span': [ 'class', 'style' ], 'label': [ 'class' ], 'input': [ 'class', 'type', 'disabled' ], 'code': [ 'class' ], 'ul': [ 'class' ], 'table': [ 'class' ], 'en-media': [ 'hash' ] }, allowedSchemes: ['http', 'https', 'ftp', 'mailto', 'data', 'evernote'], transformTags: { // 'h5': sanitizeHtml.simpleTransform('strong', {}, false), 'table': sanitizeHtml.simpleTransform('table', {}, false) }, }); return result.replace(//gi, '
') .replace(/<\/table>/gi, '
') .replace(/
<\/div>/gi, '') .replace(/
/gi, '

') .replace(/<\/h5>/gi, '

') .replace(/

/gi, '

') .replace(/<\/h4>/gi, '

') .replace(/opt<\/span>/gi, '') .replace(/

.*new (BackendScriptApi|FrontendScriptApi).*<\/h2>/gi, '') ; } function findNoteMeta(noteMeta, name, notePath) { if (noteMeta.title === name) { return { noteMeta, filePath: '/' + noteMeta.dirFileName, notePath }; } for (const childMeta of noteMeta.children || []) { const ret = findNoteMeta(childMeta, name, [...notePath, childMeta.noteId]); if (ret) { return { noteMeta: ret.noteMeta, filePath: '/' + noteMeta.dirFileName + ret.filePath, notePath: ret.notePath }; } } return null; } function rewriteLinks(rootFilePath, files, dir) { let content = fs.readFileSync(rootFilePath).toString(); for (const file of files) { content = content.replaceAll(`href="${file}.html"`, `href="${dir}/${file}.html"`); } fs.writeFileSync(rootFilePath, content); } function createChildren(files, notePath) { let positionCounter = 0; const camelCase = name => { if (name === 'module-sql') { return 'moduleSql'; } else if (/[^a-z]+/i.test(name)) { throw new Error(`Bad name '${name}'`); } return name.charAt(0).toLowerCase() + name.substr(1); }; return files.map(file => { positionCounter += 10; const noteId = "_" + camelCase(file); return { "isClone": false, "noteId": noteId, "notePath": [ ...notePath, '_' + camelCase(file) ], "title": file, "notePosition": positionCounter, "prefix": null, "isExpanded": false, "type": "text", "mime": "text/html", "attributes": [], "format": "html", "dataFileName": file + ".html" } }); } function getScriptApiMeta() { return [ { "isClone": false, "noteId": "_frontendApi", "notePath": [ ...scriptApiDocsRootNotePath, "_frontendApi" ], "title": "API docs", "notePosition": 10, "prefix": null, "isExpanded": false, "type": "text", "mime": "text/html", "attributes": [], "format": "html", "dataFileName": "FrontendScriptApi.html", "dirFileName": "FrontendScriptApi", "children": createChildren(FE_FILES, [ ...scriptApiDocsRootNotePath, "_frontendApi" ]) }, { "isClone": false, "noteId": "_backendApi", "notePath": [ ...scriptApiDocsRootNotePath, "_backendApi" ], "title": "API docs", "notePosition": 20, "prefix": null, "isExpanded": false, "type": "text", "mime": "text/html", "attributes": [], "format": "html", "dataFileName": "BackendScriptApi.html", "dirFileName": "BackendScriptApi", "children": createChildren(BE_FILES, [ ...scriptApiDocsRootNotePath, "_backendApi" ]) } ]; }