#!/usr/bin/env node // Usage: node test.js // Script that creates index.html out of web/template.html and README.md. // It is written in JS because this code used to be executed on the client side. // To install dependencies run: // $ npm install -g jsdom jquery showdown highlightjs // If running on mac and modules cant be found after instalation add: // export NODE_PATH=/usr/local/lib/node_modules // to the ~/.bash_profile or ~/.bashrc file and run '$ bash'. const fs = require('fs'); const jsdom = require('jsdom'); const showdown = require('showdown'); const hljs = require('highlightjs'); const TOC = '
' + '

Contents

\n' + '
ToC = {\n' +
  '    \'1. Collections\': [List, Dict, Set, Range, Enumerate, Namedtuple, Iterator, Generator],\n' +
  '    \'2. Types\':       [Type, String, Regex, Format, Numbers, Combinatorics, Datetime],\n' +
  '    \'3. Syntax\':      [Args, Inline, Closure, Decorator, Class, Duck_Types, Enum, Exceptions],\n' +
  '    \'4. System\':      [Print, Input, Command_Line_Arguments, Open, Path, Command_Execution],\n' +
  '    \'5. Data\':        [CSV, JSON, Pickle, SQLite, Bytes, Struct, Array, MemoryView, Deque],\n' +
  '    \'6. Advanced\':    [Threading, Introspection, Metaprograming, Operator, Eval, Coroutine],\n' +
  '    \'7. Libraries\':   [Progress_Bar, Plot, Table, Curses, Logging, Scraping, Web, Profile,\n' +
  '                       NumPy, Image, Audio]\n' +
  '}\n' +
  '
\n'; const DIAGRAM_1_A = '+---------+-------------+\n' + '| Classes | Metaclasses |\n' + '+---------+-------------|\n' + '| MyClass > MyMetaClass |\n' + '| | v |\n' + '| object ---> type <+ |\n' + '| | ^ +---+ |\n' + '| str -------+ |\n' + '+---------+-------------+\n'; const DIAGRAM_1_B = '┏━━━━━━━━━┯━━━━━━━━━━━━━┓\n' + '┃ Classes │ Metaclasses ┃\n' + '┠─────────┼─────────────┨\n' + '┃ MyClass → MyMetaClass ┃\n' + '┃ │ ↓ ┃\n' + '┃ object ───→ type ←╮ ┃\n' + '┃ │ ↑ ╰───╯ ┃\n' + '┃ str ───────╯ ┃\n' + '┗━━━━━━━━━┷━━━━━━━━━━━━━┛\n'; const DIAGRAM_2_A = '+---------+-------------+\n' + '| Classes | Metaclasses |\n' + '+---------+-------------|\n' + '| MyClass | MyMetaClass |\n' + '| v | v |\n' + '| object <--- type |\n' + '| ^ | |\n' + '| str | |\n' + '+---------+-------------+\n'; const DIAGRAM_2_B = '┏━━━━━━━━━┯━━━━━━━━━━━━━┓\n' + '┃ Classes │ Metaclasses ┃\n' + '┠─────────┼─────────────┨\n' + '┃ MyClass │ MyMetaClass ┃\n' + '┃ ↓ │ ↓ ┃\n' + '┃ object ←─── type ┃\n' + '┃ ↑ │ ┃\n' + '┃ str │ ┃\n' + '┗━━━━━━━━━┷━━━━━━━━━━━━━┛\n'; function main() { const html = getMd(); initDom(html); modifyPage(); const template = readFile('web/template.html'); const tokens = template.split('
'); const text = `${tokens[0]} ${document.body.innerHTML} ${tokens[1]}`; writeToFile('index.html', text); } function initDom(html) { const { JSDOM } = jsdom; const dom = new JSDOM(html); const $ = (require('jquery'))(dom.window); global.$ = $; global.document = dom.window.document; } function getMd() { var readme = readFile('README.md'); readme = switchClassDiagrams(readme); const converter = new showdown.Converter(); return converter.makeHtml(readme); } function switchClassDiagrams(readme) { readme = readme.replace(DIAGRAM_1_A, DIAGRAM_1_B) return readme.replace(DIAGRAM_2_A, DIAGRAM_2_B) } function modifyPage() { removeOrigToc(); addToc(); insertLinks(); unindentBanner(); highlightCode(); } function removeOrigToc() { const headerContents = $('#contents'); const contentsList = headerContents.next(); headerContents.remove(); contentsList.remove(); } function addToc() { const nodes = $.parseHTML(TOC); $('#main').before(nodes); } function insertLinks() { $('h2').each(function() { const aId = $(this).attr('id'); const text = $(this).text(); const line = `#${text}`; $(this).html(line); }); } function unindentBanner() { const montyImg = $('img').first(); montyImg.parent().addClass('banner'); const downloadPraragrapth = $('p').first(); downloadPraragrapth.addClass('banner'); } function highlightCode() { setApaches(['', '', '
', '', '', '']); $('code').not('.python').not('.text').not('.bash').not('.apache').addClass('python'); $('code').each(function(index) { hljs.highlightBlock(this); }); fixClasses() } function setApaches(elements) { for (el of elements) { $(`code:contains(${el})`).addClass('apache'); } } function fixClasses() { // Changes class="hljs-keyword" to class="hljs-title" of 'class' keyword. $('.hljs-class').filter(':contains(class \')').find(':first-child').removeClass('hljs-keyword').addClass('hljs-title') } function readFile(filename) { try { return fs.readFileSync(filename, 'utf8'); } catch(e) { console.error('Error:', e.stack); } } function writeToFile(filename, text) { try { return fs.writeFileSync(filename, text, 'utf8'); } catch(e) { console.error('Error:', e.stack); } } main();