UNPKG

ecmarkup

Version:

Custom element definitions and core utilities for markup that specifies ECMAScript and related technologies.

170 lines (140 loc) 4.73 kB
module.exports = Spec; var Path = require('path'); var utils = require('./utils'); var Promise = require('bluebird'); var Import = require('./Import'); var Clause = require('./Clause'); var ClauseNumbers = require('./clauseNums'); var Algorithm = require('./Algorithm'); var Note = require('./Note'); var Production = require('./Production'); var hljs = require('highlight.js'); function Spec(rootPath, fetch, doc) { this.rootPath = rootPath; this.rootDir = Path.dirname(this.rootPath); this.doc = doc; this.fetch = fetch; this.subclauses = []; this._numberer = ClauseNumbers.iterator(); this.externalBiblio = { ops: {} }; this.biblio = { ops: {} }; } Spec.prototype.build = function() { var s = Date.now(); return this.inlineAllImports() .then(this.loadES6Biblio.bind(this)) .then(this.loadBiblios.bind(this)) .then(this.buildClauses.bind(this)) .then(this.buildToc.bind(this)) .then(this.buildAlgs.bind(this)) .then(this.buildNotes.bind(this)) .then(this.buildProductions.bind(this)) .then(this.highlightCode.bind(this)) .then(function() { return '<!doctype html>\n' + this.doc.documentElement.innerHTML; }.bind(this)); }; Spec.prototype.buildNotes = function() { var notes = this.doc.querySelectorAll('emu-note'); for(var i = 0; i < notes.length; i++) { new Note(this, notes[i]).build(); } }; Spec.prototype.buildAlgs = function() { var algs = this.doc.querySelectorAll('emu-alg'); var builders = []; // initialize first to collect any aoids for(var i = 0; i < algs.length; i++) { builders.push(new Algorithm(this, algs[i])); } // build each builders.forEach(function(b) { b.build(); }); }; Spec.prototype.loadES6Biblio = function() { return this.fetch(Path.join(__dirname, '../es6biblio.json')) .then(function(es6bib) { es6bib = JSON.parse(es6bib); Object.keys(es6bib).forEach(function(site) { Object.keys(es6bib[site]).forEach(function(alg) { this.externalBiblio.ops[alg] = site + es6bib[site][alg]; }, this); }, this); }.bind(this)); }; // biblio paths are always relative to root document Spec.prototype.loadBiblios = function() { var spec = this; var bibs = Array.prototype.slice.call(this.doc.querySelectorAll('emu-biblio')); return Promise.all( bibs.map(function(bib) { var path = Path.join(spec.rootDir, bib.getAttribute('href')); return spec.fetch(path) .then(function(contents) { contents = JSON.parse(contents); Object.keys(contents).forEach(function(site) { var ops = contents[site]["abstract operations"]; Object.keys(ops).forEach(function(alg) { spec.externalBiblio.ops[alg] = site + ops[alg]; }); }); }); }) ); }; Spec.prototype.inlineAllImports = function() { var imports = this.doc.querySelectorAll('link[rel=import]'); imports = Array.prototype.slice.call(imports); return this.inlineImports(imports); }; Spec.prototype.inlineImports = function(imports, rootDir) { return Promise.all(imports.map(function(importNode) { var imp = new Import(this, importNode, rootDir || this.rootDir); return imp.inline(); }, this)); }; Spec.prototype.buildClauses = function() { var clauses = Array.prototype.slice.call( this.doc.querySelectorAll('EMU-INTRO, EMU-CLAUSE, EMU-ANNEX') ); clauses.forEach(function(clauseNode) { var clause = new Clause(this, clauseNode); clause.build(); }, this); }; Spec.prototype.buildToc = function() { var html = buildToc(this); var tocContainer = this.doc.createElement('div'); tocContainer.innerHTML = '<h2>Table of Contents</h2>' + html; var intro = this.doc.querySelector('emu-intro, emu-clause'); intro.parentNode.insertBefore(tocContainer, intro); }; Spec.prototype.getNextClauseNumber = function(depth, isAnnex) { return this._numberer.next(depth, isAnnex).value; }; Spec.prototype.buildProductions = function() { var prods = this.doc.querySelectorAll('emu-production'); for(var i = 0; i < prods.length; i++) { new Production(this, prods[i]).build(); } }; Spec.prototype.highlightCode = function() { var codes = this.doc.querySelectorAll('pre code'); for(var i = 0; i < codes.length; i++) { hljs.highlightBlock(codes[i]); } } function buildToc(spec, level) { level = level || spec; var html = '<ol class="toc">'; level.subclauses.forEach(function(sub) { html += '<li><a href="#' + sub.id + '"><span class="secnum">' + sub.number + '</span> ' + sub.title + '</a>'; if(sub.subclauses.length > 0) html += buildToc(spec, sub); html += '</li>'; }); html += '</ol>'; return html; }