/* * * impress.js website - build.js * * Developed 2023 by Janis Hutz * */ /* We will convert certain MD files to html and include them in the documentation. This mostly includes the plugin documentation. If there is no MD file in the directory, there will be no documentation. The script will also automatically build the nav menu and copy all the necessary files to the correct places. */ const fs = require( 'fs' ); const path = require( 'path' ); const mdhtml = require( 'markdown-it' ); const md2html = new mdhtml(); const docRoot = path.join( __dirname + '/../' ); const ls = require( 'ls' ); const prompt = require( 'prompt-sync' )( { sigint: true } ); const pluginsPath = path.join( __dirname + '/../../../src/plugins' ); let plugins = fs.readdirSync( pluginsPath ); delete plugins[0]; if ( prompt( 'Do you want to regenerate the API reference? (y/N) ' ).toLowerCase() == 'y' ) { console.log( 'Regenerating API reference' ); parseDocumentationMD(); } if ( prompt( 'Do you want to regenerate the getting started guide? (y/N) ' ).toLowerCase() == 'y' ) { console.log( 'Regenerating Getting Started Guide' ); storeHTML( generateGettingStarted( md2html.render( '' + fs.readFileSync( path.join( __dirname + '/../../../GettingStarted.md' ) ) ) ), 'gettingStarted', '' ); } let docPages = fs.readdirSync( __dirname + '/../../../website/docs/reference' ); if ( prompt( 'Do you want to regenerate the plugins documentation? (y/N) ' ).toLowerCase() == 'y' ) { console.log( 'regenerating plugins documentation' ); let pluginsHome = md2html.render( fs.readFileSync( path.join( pluginsPath + '/README.md' ) ).toString() ); /* Generate the plugins index.html from README.md */ for ( let letter in pluginsHome ) { if ( pluginsHome[ letter ] === '<' ) { if ( pluginsHome.slice( parseInt( letter ), parseInt( letter ) + 9 ) === ''; } else if ( link.slice( 5, 7 ) === '../' ) { newLink = ''; } else if ( link.slice( 0, 3 ) === '../' ) { newLink = ''; } else { newLink = ''; } } else if ( link.slice( 0, 8 ) === 'https://' || link.slice( 0, 7 ) === 'http://' ) { newLink = ''; } else if ( link.slice( 0, 2 ) === './' || link.slice( 0, 1 ) !== '/' || link.slice( 0, 1 ) !== '.' ) { if ( link.slice( parseInt( link.length ) - 9, parseInt( link.length ) ) === 'README.md' ) { newLink = ''; } else { newLink = ''; }; } else { throw 'INVALID LINK FOUND IN PLUGINS README! Please fix and rerun the script'; } pluginsHome = pluginsHome.slice( 0, parseInt( letter ) ) + newLink + pluginsHome.slice( parseInt( letter) + i + 2, parseInt( pluginsHome.length ) ); }; }; }; storeHTML( pluginsHome, 'index', 'plugins' ); /* Generate the rest of the plugins documentation from their READMEs and warn if no README was found */ for ( let item in plugins ) { fs.readFile( path.join( pluginsPath + '/' + plugins[item] + '/README.md' ), ( error, data ) => { if ( error ) { console.log( 'NO README found for ' + path.join( pluginsPath + '/' + plugins[item] ) + ' PLEASE MAKE SURE YOU HAVE CREATED A README!' ); } else { ( async () => { let html = md2html.render( '' + data ); storeHTML( await findLinks( html, path.join( pluginsPath + '/' + plugins[item] ) ), plugins[item], 'plugins' ); } ) (); }; } ); }; for ( let obj in docPages ) { if ( docPages[obj] == 'index.html' ) { delete docPages[obj]; }; } } console.log( 'regenerating Nav' ); generateNav (); buildExamplesPage(); /* This function finds links. The reason for this is possible incompatibilities with links on the website */ async function findLinks ( html, path ) { let returnHTML = html; for ( let letter in returnHTML ) { if ( returnHTML[letter] === '<' ) { if ( returnHTML.slice( parseInt( letter ), parseInt( letter ) + 9 ) === ''; } else if ( link.slice( 0, 2 ) === '..' ) { // here we map the relative path to an absolute path that can be used with the GitHub repo. while ( link.slice( pos, pos + 3 ) === '../' ) { pos += 3; let pathPos = 1; while ( filepath.slice( parseInt( filepath.length ) - pathPos, parseInt( filepath.length ) - pathPos + 1 ) !== '/' ) { pathPos += 1; }; filepath = filepath.slice( 0, parseInt( filepath.length ) - pathPos + 1 ); }; // Here we find the impress.js root in the filepath to remove it and finish the link generation let fsPos = 0; while ( filepath.slice( parseInt( filepath.length ) - fsPos - 10, parseInt( filepath.length ) - fsPos ) !== 'impress.js' ) { fsPos += 1; }; let fpSlice = filepath.slice( parseInt( filepath.length ) - fsPos + 1, parseInt( filepath.length ) ); let linkSlice = link.slice( pos, link.length ); // now let's assemble a link and add it back into the html if ( link.slice( link.length - 3, link.length ).includes( '.' ) ) { return ''; } else { return ''; }; } else if ( link.slice( 0, 1 ) !== '.' && link.slice( 0, 1 ) !== '/' ) { let fsPos = 0; while ( filepath.slice( parseInt( filepath.length ) - fsPos - 10, parseInt( filepath.length ) - fsPos ) !== 'impress.js' ) { fsPos += 1; }; let fpSlice = filepath.slice( parseInt( filepath.length ) - fsPos + 1, parseInt( filepath.length ) ) + '/'; if ( link.slice( link.length - 3, link.length ).includes( '.' ) ) { return ''; } else { return ''; }; } else if ( link.slice( 0, 7 ) === 'http://' || link.slice( 0, 8 ) === 'https://' ) { return ''; } else if ( link.slice( 0, 1 ) === '/' && link.slice( 1, 2 ) !== '.' ) { if ( link.slice( link.length - 3, link.length ).includes( '.' ) ) { if ( link === '/GettingStarted.md' ) { return ''; } else if ( link === '/DOCUMENTATION.md' ) { return ''; } else { return ''; } } else { return ''; }; } else { throw Error( 'Invalid link found! Link is: "' + link + '" in file: ' + filepath + '/README.md' ); }; }; /* This function generates & stores the HTML in the correct directory */ function storeHTML ( html, path, type ) { let fileOut = ` ${path} :: ${type} | DOCS - impress.js
` + html + `
`; fs.writeFileSync( docRoot + '/' + type + '/' + path + '.html', fileOut ); }; /* This function, as the name implies, generates the navbar on the side in the docs. */ function generateNav () { let fileStruct = `
`; fs.writeFileSync( docRoot + '/nav.html', fileStruct ); }; function parseDocumentationMD () { let doc = '' + fs.readFileSync( path.join( __dirname + '/../../../DOCUMENTATION.md' ) ); let lastHashtagPos = 0; let posArray = []; for ( let letter in doc ) { if ( doc[letter] == '#' ) { if ( doc.slice( parseInt( letter ), parseInt( letter ) + 3 ) === '###' || doc.slice( parseInt( letter ), parseInt( letter ) + 4 ) === '####' ) { } else if ( doc.slice( parseInt( letter ), parseInt( letter ) + 2 ) === '##' && lastHashtagPos + 1 < parseInt( letter ) ) { posArray.push(letter); }; lastHashtagPos = parseInt( letter ); }; }; let titles = {}; for ( let item in posArray ) { let titleArea = doc.slice( parseInt( posArray[item] ), parseInt( posArray[item] + 20 ) ); let title = ''; for ( let pos in titleArea ) { if ( titleArea[pos] === '\n' ) { title = titleArea.slice( 3, pos ); break; }; }; let page = md2html.render( doc.slice( parseInt( posArray[parseInt( item )] ), parseInt( posArray[parseInt( item ) + 1] ) || parseInt( doc.length ) ) ); for ( let letter in page ) { let titleTag = page.slice( parseInt( letter ), parseInt( letter ) + 4 ); if ( titleTag === '

' || titleTag === '

' || titleTag === '

' || titleTag === '

' ) { let i = 4; while ( page.slice( parseInt( letter ) + i, parseInt( letter ) + i + 1 ) !== '<' ) { i += 1; }; let heading = '' + page.slice( parseInt( letter ) + 4, parseInt( letter ) + i ); let output = ''; for ( let pos in heading ) { let letter = heading[ pos ]; if ( letter === ' ' || letter === '.' || letter === ',' ) { output += '-'; } else if ( letter === '(' || letter === ')' || letter === '[' || letter === ']' || letter === '|' ) { } else { output += letter; }; }; titles[ output.toLowerCase() ] = title; }; }; } for ( let item in posArray ) { let titleArea = doc.slice( parseInt( posArray[item] ), parseInt( posArray[item] + 20 ) ); let title = ''; for ( let pos in titleArea ) { if ( titleArea[pos] === '\n' ) { title = titleArea.slice( 3, pos ); break; }; }; let page = md2html.render( doc.slice( parseInt( posArray[parseInt( item )] ), parseInt( posArray[parseInt( item ) + 1] ) || parseInt( doc.length ) ) ); for ( let letter in page ) { let titleTag = page.slice( parseInt( letter ), parseInt( letter ) + 4 ); if ( page[letter] === '<' ) { if ( page.slice( parseInt( letter ), parseInt( letter ) + 9 ) === '' || titleTag === '

' || titleTag === '

' || titleTag === '

' ) { let i = 4; while ( page.slice( parseInt( letter ) + i, parseInt( letter ) + i + 1 ) !== '<' ) { i += 1; }; let heading = '' + page.slice( parseInt( letter ) + 4, parseInt( letter ) + i ); let output = ''; for ( let pos in heading ) { let letter = heading[ pos ]; if ( letter === ' ' || letter === '.' || letter === ',' ) { output += '-'; } else if ( letter === '(' || letter === ')' || letter === '[' || letter === ']' || letter === '|' ) { } else { output += letter; }; }; page = page.slice( 0, parseInt( letter ) + 3 ) + ' id="' + output.toLowerCase() + '">' + page.slice( parseInt( letter ) + 4, parseInt( page.length ) ); }; }; storeHTML( page, title, 'reference' ); }; }; } function generateGettingStarted ( inputHTML ) { let html = inputHTML; for ( let letter in html ) { if ( html[letter] === '<' ) { if ( html.slice( parseInt( letter ), parseInt( letter ) + 9 ) === '' + dir + '\n'; }; }); let html = ` Example presentations

Exam­ples

${ html_list }
`; fs.writeFileSync( path.join( __dirname + '/../../demo/examples/index.html' ), html ); }