Skip to content

Commit

Permalink
Refactor to externalise core API
Browse files Browse the repository at this point in the history
This refactor externalises the API (process/ use / parse /
transform / compile). The two reasons for that:

*   Now **retext** can use a similar API, without duplicate
    code;

*   Less commits relating to API design will be in this
    repository.

This does change the exports object of `lib/parse` and
`lib/compile`, in that they previously exposed different
interfaces (a function with a constructor on top). This
was normalized into just a constructor (`Parser` /
`Compiler`) which receive a virtual file and settings,
and expose respectivly either a `parse` or a `compile`
method.

This additionally changes some internals (where plug-ins)
are stored, and removes the limitation of not allowing
multiple equal attachers.
  • Loading branch information
wooorm committed Jul 31, 2015
1 parent ed3e49a commit 9892ec4
Show file tree
Hide file tree
Showing 8 changed files with 3,498 additions and 1,753 deletions.
3 changes: 1 addition & 2 deletions component.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@
"jonschlinkert/repeat-string": "^1.5.2",
"component/trim": "^0.0.1",
"wooorm/trim-trailing-lines": "^1.0.0",
"segmentio/ware": "^1.2.0",
"wooorm/vfile": "^1.0.0"
"wooorm/unified": "^1.0.0"
},
"repository": "wooorm/mdast",
"scripts": [
Expand Down
327 changes: 10 additions & 317 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,324 +12,17 @@
* Dependencies.
*/

var Ware = require('ware');
var VFile = require('vfile');
var extend = require('extend.js');
var parser = require('./lib/parse.js');
var stringifier = require('./lib/stringify.js');
var utilities = require('./lib/utilities.js');
var unified = require('unified');
var Parser = require('./lib/parse.js');
var Compiler = require('./lib/stringify.js');

/*
* Methods.
* Exports.
*/

var Parser = parser.Parser;
var parseProto = Parser.prototype;
var Compiler = stringifier.Compiler;
var compileProto = Compiler.prototype;

/**
* Throws if passed an exception.
*
* Here until the following PR is merged into
* segmentio/ware:
*
* https://github.com/segmentio/ware/pull/21
*
* @param {Error?} exception
*/
function fail(exception) {
if (exception) {
throw exception;
}
}

/**
* Create a custom, cloned, Parser.
*
* @return {Function}
*/
function constructParser() {
var customProto;
var expressions;
var key;

/**
* Extensible prototype.
*/
function CustomProto() {}

CustomProto.prototype = parseProto;

customProto = new CustomProto();

/**
* Extensible constructor.
*/
function CustomParser() {
Parser.apply(this, arguments);
}

CustomParser.prototype = customProto;

/*
* Construct new objects for things that plugin's
* might modify.
*/

customProto.blockTokenizers = extend({}, parseProto.blockTokenizers);
customProto.blockMethods = extend([], parseProto.blockMethods);
customProto.inlineTokenizers = extend({}, parseProto.inlineTokenizers);
customProto.inlineMethods = extend([], parseProto.inlineMethods);

expressions = parseProto.expressions;
customProto.expressions = {};

for (key in expressions) {
customProto.expressions[key] = extend({}, expressions[key]);
}

return CustomParser;
}

/**
* Create a custom, cloned, Compiler.
*
* @return {Function}
*/
function constructCompiler() {
var customProto;

/**
* Extensible prototype.
*/
function CustomProto() {}

CustomProto.prototype = compileProto;

customProto = new CustomProto();

/**
* Extensible constructor.
*/
function CustomCompiler() {
Compiler.apply(this, arguments);
}

CustomCompiler.prototype = customProto;

return CustomCompiler;
}

/**
* Construct an MDAST instance.
*
* @constructor {MDAST}
*/
function MDAST() {
var self = this;

if (!(self instanceof MDAST)) {
return new MDAST();
}

self.ware = new Ware();
self.attachers = [];

self.Parser = constructParser();
self.Compiler = constructCompiler();
}

/**
* Attach a plugin.
*
* @param {Function|Array.<Function>} attach
* @param {Object?} [options]
* @param {FileSet?} [fileSet] - Optional file-set,
* passed by the CLI.
* @return {MDAST}
*/
function use(attach, options, fileSet) {
var self = this;
var index;
var transformer;

if (!(self instanceof MDAST)) {
self = new MDAST();
}

/*
* Multiple attachers.
*/

if ('length' in attach && typeof attach !== 'function') {
index = -1;

while (attach[++index]) {
self.use(attach[index], options, fileSet);
}

return self;
}

/*
* Single plugin.
*/

if (self.attachers.indexOf(attach) === -1) {
transformer = attach(self, options, fileSet);

self.attachers.push(attach);

if (transformer) {
self.ware.use(transformer);
}
}

return self;
}

/**
* Apply transformers to `node`.
*
* @param {Node} ast
* @param {VFile?} [file]
* @param {Function?} [done]
* @return {Node} - `ast`.
*/
function run(ast, file, done) {
var self = this;

if (typeof file === 'function') {
done = file;
file = null;
}

file = new VFile(file);

done = typeof done === 'function' ? done : fail;

if (typeof ast !== 'object' && typeof ast.type !== 'string') {
utilities.raise(ast, 'ast');
}

/*
* Only run when this is an instance of MDAST.
*/

if (self.ware) {
self.ware.run(ast, file, done);
} else {
done(null, ast, file);
}

return ast;
}

/**
* Wrapper to pass a file to `parser`.
*/
function parse(value, options) {
var file = new VFile(value);
var ast = file.namespace('mdast').ast = parser.call(this, file, options);

return ast;
}

/**
* Wrapper to pass a file to `stringifier`.
*/
function stringify(ast, file, options) {
if (options === null || options === undefined) {
options = file;
file = null;
}

if (!file && ast && !ast.type) {
file = ast;
ast = null;
}

file = new VFile(file);

if (!ast) {
ast = file.namespace('mdast').ast || ast;
}

return stringifier.call(this, ast, file, options);
}

/**
* Parse a value and apply transformers.
*
* @param {string|VFile} value
* @param {Object?} [options]
* @param {Function?} [done]
* @return {string?}
*/
function process(value, options, done) {
var file = new VFile(value);
var self = this instanceof MDAST ? this : new MDAST();
var result = null;
var ast;

if (typeof options === 'function') {
done = options;
options = null;
}

if (!options) {
options = {};
}

/**
* Invoked when `run` completes. Hoists `result` into
* the upper scope to return something for sync
* operations.
*/
function callback(exception) {
if (exception) {
(done || fail)(exception);
} else {
result = self.stringify(ast, file, options);

if (done) {
done(null, result, file);
}
}
}

ast = self.parse(file, options);

self.run(ast, file, callback);

return result;
}

/*
* Methods.
*/

var proto = MDAST.prototype;

proto.use = use;
proto.parse = parse;
proto.run = run;
proto.stringify = stringify;
proto.process = process;

/*
* Functions.
*/

MDAST.use = use;
MDAST.parse = parse;
MDAST.run = run;
MDAST.stringify = stringify;
MDAST.process = process;

/*
* Expose `mdast`.
*/

module.exports = MDAST;
module.exports = unified({
'name': 'mdast',
'type': 'ast',
'Parser': Parser,
'Compiler': Compiler
});
Loading

0 comments on commit 9892ec4

Please sign in to comment.