[discussion] Overridable public API.
Based from discussions in #152 and #159, making the public API an adapter to a private API might be nice so that people can create "plugins" for the community by simply overriding some or all of dox's public methods.
To restore dox's functionality (i.e. to be able to use dox with multiple types of code in the same running program) I was thinking there could be a simple function that restores all the public methods to their original state simply by re-adapting to the internal API (not by reference, but by closure, for privacy).
@trusktr @ChiperSoft I'm just wondering – have you seen such plugin architectures in the wild? It sounds awesomely simple, but I'm having second thoughts if it scales well.
I mean – as I see it, it would be unsafe to use two of such "plugins" at once.
@tomekwi Good question! Can you think of a scenario where it might not scale?
var dox0 = require("dox");
var dox1 = require("dox-css")(dox0);
var dox = require("dox-markdown")(dox1);
Suppose dox-css and dox-markdown both modify the same function. I would be a shot in the dark if one plugin is compatible with another.
BTW, I've picked up this require("plugin")(require("base-lib")) pattern in gulp-help. It does its job well in simple cases.
Having an explicit api for extension isn't nessisary. Simply changing dox to invoke functions via this instead of exports would make the lib extensible via mixins.
var dox = Object.assign(
require('dox'),
require('dox-css')
require('dox-markdown')
);
Good idea!
As a matter of fact, also with require("dox-css")(require("dox")) using this is the only thing required on dox side. The good part is, dox-css can access and extend original dox functions:
// dox-css/index.js
export default (originalDox) => {
return Object.assign({}
, originalDox
// We want to extend `dox.parseComments`
, { parseComments (...args) {
// First we apply the original `dox` function
let result = originalDox.parseComments(...args);
// Here we can process the result
return processedResult;
}
}
);
};
This way we leave dox untouched and extend its functions instead of overriding them (like decorators in python).
It would also solve the problem of scalability to some extent. As long as plugin authors extend functions this way, we can safely do:
let dox = require("dox-markdown")(
require("dox-css")(
require("dox")
)
)
– in this case dox-markdown extends functions of dox-css which themselves can be extended functions of dox.
It would probably be better if extensions were added via Object.create and then used Object.getPrototypeOfto get at the original.
module.exports = exports = function (dox) {
dox = Object.create(dox);
return Object.assign(dox, exports);
}
exports.parseComments = function () {
var result = Object.getPrototypeOf(this).parseComments.apply(this, arguments);
}
This way you're able to expose the new functions in case other extensions want to use them.
Good point – that'd be lighter as well as the functions wouldn't need to be copied over and created.
Only the prototype chain might get quite deep – so you never really know if you're taking the real dox or an extended clone. In our example:
// dox-css/index.js
module.exports = exports = function (dox) {
dox = Object.create(dox); // This is indeed dox
return Object.assign(dox, exports);
}
exports.parseComments = function () {
var result = Object.getPrototypeOf(this).parseComments.apply(this, arguments);
// dox.parseComments gets called.
}
// dox-markdown/index.js
module.exports = exports = function (dox) {
dox = Object.create(dox); // This is dox-css
return Object.assign(dox, exports);
}
exports.parseComments = function () {
var result = Object.getPrototypeOf(this).parseComments.apply(this, arguments);
// doxCSS.parseComments gets called.
}
I don't think that's bad however. After all, every plugin will likely change one aspect of a function. No chance someone will use dox-markdown and dox-creole at the same time.
:+1: