Skip to content

Commit

Permalink
Add --watch option
Browse files Browse the repository at this point in the history
  • Loading branch information
bterlson committed Aug 27, 2015
1 parent f0e2dfa commit 99a9ab8
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 34 deletions.
1 change: 1 addition & 0 deletions bin/args.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = require('nomnom')
.help('Compile ecmarkup documents to html by passing your input file and output file.')
.options({
help: { abbr: 'h', flag: true, help: 'Display this help message' },
watch: { abbr: 'w', flag: true, help: 'Rebuild when files change' },
biblio: { abbr: 'b', metavar: 'FILE', help: 'Write a biblio file to FILE' },
css: { metavar: 'FILE', help: 'Write Emu CSS dependencies to FILE' },
js: { metavar: 'FILE', help: 'Write Emu JS dependencies to FILE' },
Expand Down
72 changes: 57 additions & 15 deletions bin/ecmarkup.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,69 @@ const Promise = require('bluebird');
const Path = require('path');
const fs = require('fs');
const readFile = Promise.promisify(fs.readFile);
const utils = require('../lib/utils');
const debounce = require('promise-debounce');

function fetch(path) {
return readFile(path, 'utf8');
}

ecmarkup.build(args.infile, fetch, args).then(function (spec) {
if (args.biblio) {
fs.writeFileSync(args.biblio, JSON.stringify(spec.exportBiblio()), 'utf8');
}
const build = debounce(function build() {
return ecmarkup.build(args.infile, fetch, args).then(function (spec) {
if (args.biblio) {
if (args.verbose) {
utils.logVerbose('Writing biblio file to ' + args.biblio);
}
fs.writeFileSync(args.biblio, JSON.stringify(spec.exportBiblio()), 'utf8');
}

if (args.outfile) {
fs.writeFileSync(args.outfile, spec.toHTML(), 'utf8');
} else {
process.stdout.write(spec.toHTML());
}
if (args.outfile) {
if (args.verbose) {
utils.logVerbose('Writing output to ' + args.outfile);
}
fs.writeFileSync(args.outfile, spec.toHTML(), 'utf8');
} else {
process.stdout.write(spec.toHTML());
}

if (args.css) {
fs.writeFileSync(args.css, fs.readFileSync(Path.join(__dirname, '../css/elements.css')));
}
if (args.css) {
if (args.verbose) {
utils.logVerbose('Writing css file to ' + args.css);
}
fs.writeFileSync(args.css, fs.readFileSync(Path.join(__dirname, '../css/elements.css')));
}

if (args.js) {
fs.writeFileSync(args.js, fs.readFileSync(Path.join(__dirname, '../js/menu.js')));
}
if (args.js) {
if (args.verbose) {
utils.logVerbose('Writing css file to ' + args.css);
}
fs.writeFileSync(args.js, fs.readFileSync(Path.join(__dirname, '../js/menu.js')));
}

return spec;
});
});

if (args.watch) {
let watching = {};
build().then(function(spec) {
let toWatch = spec.imports.concat(args.infile);

// remove any files that we're no longer watching
Object.keys(watching).forEach(function(file) {
if (toWatch.indexOf(file) === -1) {
watching[file].close();
delete watching[file];
}
});

// watch any new files
toWatch.forEach(function(file) {
if (!watching[file]) {
watching[file] = fs.watch(file, build);
}
});
});
} else {
build();
}
1 change: 1 addition & 0 deletions lib/Import.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module.exports = class Import extends Builder {
build(rootDir) {
const href = this.node.getAttribute('href');
const importPath = Path.join(rootDir || this.spec.rootDir, href);
this.spec.imports.push(importPath);

return this.spec.fetch(importPath)
.then(utils.htmlToDoc)
Expand Down
11 changes: 6 additions & 5 deletions lib/Spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ module.exports = class Spec {
this.doc = doc;
this.fetch = fetch;
this.subclauses = [];
this.imports = [];
this._numberer = ClauseNumbers.iterator();
this._figureCounts = {
table: 0,
Expand Down Expand Up @@ -77,10 +78,10 @@ module.exports = class Spec {
buildAll(selector, Builder, opts) {
opts = opts || {};

this._log('Building ' + selector + '...');

let elems;
if (typeof selector === 'string') {
this._log('Building ' + selector + '...');
elems = this.doc.querySelectorAll(selector);
} else {
elems = selector;
Expand Down Expand Up @@ -157,7 +158,7 @@ module.exports = class Spec {
try {
data = yaml.safeLoad(block.textContent);
} catch (e) {
console.log('Warning: metadata block failed to parse');
utils.logWarning('metadata block failed to parse');
return;
} finally {
block.parentNode.removeChild(block);
Expand Down Expand Up @@ -194,7 +195,7 @@ module.exports = class Spec {

exportBiblio() {
if (!this.opts.location) {
console.log('Warning: no spec location specified. Biblio not generated. Try --location or setting the location in the document\'s metadata block.');
utils.logWarning('no spec location specified. Biblio not generated. Try --location or setting the location in the document\'s metadata block.');
return {};
}

Expand Down Expand Up @@ -277,9 +278,9 @@ module.exports = class Spec {
return null;
}

_log() {
_log(str) {
if (!this.opts.verbose) return;
console.log.apply(console, arguments);
utils.logVerbose(str);
}
};

Expand Down
14 changes: 7 additions & 7 deletions lib/Xref.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,26 @@ module.exports = class Xref extends Builder {
const aoid = xref.getAttribute('aoid');

if (href && aoid) {
console.log('Warning: xref can\'t have both href and aoid.');
utils.logWarning('xref can\'t have both href and aoid.');
return;
}

if (!href && !aoid) {
console.log('Warning: xref has no href or aoid.');
utils.logWarning('xref has no href or aoid.');
return;
}

if (href) {
if (href[0] !== '#') {
console.log('Warning: xref to anything other than a fragment id is not supported (is ' + href + '). Try href="#sec-id" instead.');
utils.logWarning('xref to anything other than a fragment id is not supported (is ' + href + '). Try href="#sec-id" instead.');
return;
}

const id = href.slice(1);

const entry = this.spec.lookupBiblioEntryById(id);
if (!entry) {
console.log('Warning: can\'t find clause, production, note or example with id ' + href);
utils.logWarning('can\'t find clause, production, note or example with id ' + href);
return;
}

Expand All @@ -52,7 +52,7 @@ module.exports = class Xref extends Builder {
buildFigureLink(this.spec, xref, entry.entry, 'Figure');
break;
default:
console.log('Warning: found unknown biblio entry (this is a bug, please file it)');
utils.logWarning('found unknown biblio entry (this is a bug, please file it)');
}
} else if (aoid) {
const entry = this.spec.biblio.ops[aoid] || this.spec.externalBiblio.ops[aoid];
Expand All @@ -62,7 +62,7 @@ module.exports = class Xref extends Builder {
return;
}

console.log('Warning: can\'t find abstract op with aoid ' + aoid);
utils.logWarning('can\'t find abstract op with aoid ' + aoid);
}

}
Expand Down Expand Up @@ -102,7 +102,7 @@ function buildFigureLink(spec, xref, entry, type) {
// first need to find the associated clause
const clauseEntry = spec.lookupBiblioEntryById(entry.clauseId);
if (clauseEntry.type !== 'clause') {
console.log('Warning: could not find parent clause for ' + type + ' id ' + entry.id);
utils.logWarning('could not find parent clause for ' + type + ' id ' + entry.id);
}

const parentClause = utils.parent(xref, ['EMU-CLAUSE', 'EMU-INTRO', 'EMU-ANNEX']);
Expand Down
11 changes: 11 additions & 0 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const jsdom = require('jsdom');
const Promise = require('bluebird');
const chalk = require('chalk');

exports.htmlToDoc = function (html) {
return new Promise(function (res, rej) {
Expand Down Expand Up @@ -56,3 +57,13 @@ exports.parent = function parent(node, types) {
return parent(node.parentNode, types);
};


exports.logVerbose = function(str) {
let dateString = (new Date()).toISOString();
console.log(chalk.gray('[' + dateString + '] ') + str);
};

exports.logWarning = function(str) {
let dateString = (new Date()).toISOString();
console.log(chalk.gray('[' + dateString + '] ') + chalk.red('Warning: ' + str));
};
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ecmarkup",
"version": "2.0.3",
"version": "2.1.0",
"description": "Custom element definitions and core utilities for markup that specifies ECMAScript and related technologies.",
"main": "lib/ecmarkup.js",
"scripts": {
Expand Down Expand Up @@ -33,13 +33,15 @@
"homepage": "https://github.com/bterlson/ecmarkup",
"dependencies": {
"bluebird": "^2.6.4",
"chalk": "^1.1.1",
"ecmarkdown": "^3.0.1",
"grammarkdown": "^0.1.3",
"highlight.js": "^8.6.0",
"html-escape": "^1.0.2",
"js-yaml": "^3.3.1",
"jsdom": "^5.0.1",
"nomnom": "^1.8.1"
"nomnom": "^1.8.1",
"promise-debounce": "^1.0.1"
},
"devDependencies": {
"diff": "^1.4.0",
Expand Down
18 changes: 13 additions & 5 deletions spec/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,26 @@ <h1>Getting Started</h1>
ecmarkup spec.html out.html
</pre>

<h2>Useful Options</h2>
<table>
<tr><th>Option</th><th>Description</th></tr>
<tr><td>watch</td><td>Rebuild when files change</td></tr>
<tr><td>verbose</td><td>Print verbose logging info</td></tr>
<tr><td>biblio</td><td>Emit a biblio file to the specified location</td></tr>
<tr><td>css</td><td>Emit the Ecmarkup CSS file to the specified location</td></tr>
<tr><td>js</td><td>Emit the Ecmarkup JS file to the specified location</td></tr>
<tr><td>toc</td><td>Emit table of contents. Boolean, default true.</td></tr>
<tr><td>old-toc</td><td>Emit the old style of table of contents. Boolean, default false.</td></tr>
</table>

<h2>Stylesheet</h2>
<p>Styles are provided by `elements.css` under the `css` directory. The --css command line option will emit the CSS file to a location of your choosing. You may also link to https://bterlson.github.io/ecmarkup/elements.css which will contain the latest styles for the forseeable future (though I don't promise this won't break you if you're not tracking the latest version).</p>
</emu-clause>
<emu-clause id="metadata">
<h1>Metadata</h1>
<p>There are a number of settings that allow customizations or enable generation of boilerplate. Metadata can be included in the document and passed on the command line, for example `--no-toc --title "Document 1"`. Metadata given on the command line takes precedence.</p>
<p>To add metadata to your document, use yaml syntax inside a `&lt;pre class=metadata>` element somewhere in the root of your document.</p>
<p>The following table lists the currently supported metadata:</p>
<table>
<tr><th>Option</th><th>Description</th></tr>
<tr><td>toc</td><td>Emit table of contents. Boolean, default true.</td></tr>
</table>
<p>All of the command line options can be provided in the metadata block. See the table above for a list (or consult `--help`).</p>
<h2>Example document with metadata</h2>
<pre><code class="language-html">
&lt;pre class=metadata>
Expand Down

0 comments on commit 99a9ab8

Please sign in to comment.