dgeni
Version:
Flexible JavaScript documentation generator used by both AngularJS and Angular
254 lines • 11.4 kB
JavaScript
;
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Dgeni = void 0;
/* tslint globals: require: true */
var di = require('di');
var Package_1 = require("./Package");
var processorValidation_1 = require("./legacyPackages/processorValidation");
var dependency_sort_1 = require("./util/dependency-sort");
var getInjectables_1 = require("./util/getInjectables");
var log_1 = require("./util/log");
/**
* Create an instance of the Dgeni documentation generator, loading any packages passed in as a
* parameter.
* @param {Package[]} [packages] A collection of packages to load
*/
var Dgeni = /** @class */ (function () {
function Dgeni(packages) {
var _this = this;
if (packages === void 0) { packages = []; }
this.packages = {};
if (!Array.isArray(packages)) {
throw new Error('packages must be an array');
}
// Add in the legacy validation that was originally part of the core Dgeni tool.
this.package(processorValidation_1.processorValidationPackage);
packages.map(function (p) { return _this.package(p); });
}
/**
* Load a package into dgeni
* @param package The package to load or the name of a new package to create.
* @param dependencies A collection of dependencies for this package
* @return The package that was loaded, to allow chaining
*/
Dgeni.prototype.package = function (pkg, dependencies) {
var _this = this;
if (dependencies === void 0) { dependencies = []; }
if (this.injector) {
throw new Error('injector already configured - you cannot add a new package');
}
if (typeof pkg === 'string') {
pkg = new Package_1.Package(pkg, dependencies);
}
if (!(Package_1.Package.isPackage(pkg))) {
throw new Error('package must be an instance of Package');
}
if (this.packages[pkg.name]) {
throw new Error('The "' + pkg.name + '" package has already been loaded');
}
this.packages[pkg.name] = pkg;
// Extract all inline packages and load them into dgeni;
pkg.namedDependencies = pkg.dependencies.map(function (dependency) {
if (Package_1.Package.isPackage(dependency)) {
// Only load dependent package if not already loaded
if (!_this.packages[dependency.name]) {
_this.package(dependency);
}
return dependency.name;
}
return dependency;
});
// Return the package to allow chaining
return pkg;
};
/**
* Configure the injector using the loaded packages.
*
* The injector is assigned to the `injector` property on `this`, which is used by the
* `generate()` method. Subsequent calls to this method will just return the same injector.
*
* This method is useful in unit testing services and processors as it gives an easy way to
* get hold of an instance of a ready instantiated component without having to load in all
* the potential dependencies manually:
*
* ```
* const Dgeni = require('dgeni');
*
* function getInjector() {
* const dgeni = new Dgeni();
* dgeni.package('testPackage', [require('dgeni-packages/base')])
* .factory('templateEngine', function dummyTemplateEngine() {});
* return dgeni.configureInjector();
* };
*
* describe('someService', function() {
* const someService;
* beforeEach(function() {
* const injector = getInjector();
* someService = injector.get('someService');
* });
*
* it("should do something", function() {
* someService.doSomething();
* ...
* });
* });
* ```
*/
Dgeni.prototype.configureInjector = function () {
var _this = this;
if (!this.injector) {
// Sort the packages by their dependency - ensures that services and configs are loaded in the
// correct order
var packages = this.packages = dependency_sort_1.sortByDependency(this.packages, 'namedDependencies');
// Create a module containing basic shared services
this.stopOnProcessingError = true;
var dgeniModule = new di.Module()
.value('dgeni', this)
.factory('log', log_1.logFactory)
.factory('getInjectables', getInjectables_1.getInjectablesFactory);
// Create the dependency injection container, from all the packages' modules
var modules = packages.map(function (pkg) { return pkg.module; });
modules.unshift(dgeniModule);
// Create the injector and
var injector_1 = this.injector = new di.Injector(modules);
// Apply the config blocks
packages.forEach(function (pkg) { return pkg.configFns.forEach(function (configFn) { return injector_1.invoke(configFn); }); });
// Get the the processors and event handlers
var processorMap_1 = {};
this.handlerMap = {};
packages.forEach(function (pkg) {
pkg.processors.forEach(function (processorName) {
var processor = injector_1.get(processorName);
// Update the processor's name and package
processor.name = processorName;
processor.$package = pkg.name;
// Ignore disabled processors
if (processor.$enabled !== false) {
processorMap_1[processorName] = processor;
}
});
var _loop_1 = function (eventName) {
var handlers = _this.handlerMap[eventName] = (_this.handlerMap[eventName] || []);
pkg.handlers[eventName].forEach(function (handlerName) { return handlers.push(injector_1.get(handlerName)); });
};
for (var eventName in pkg.handlers) {
_loop_1(eventName);
}
});
// Once we have configured everything sort the processors.
// This allows the config blocks to modify the $runBefore and $runAfter properties of processors.
// (Crazy idea, I know, but useful for things like debugDumpProcessor)
this.processors = dependency_sort_1.sortByDependency(processorMap_1, '$runAfter', '$runBefore');
}
return this.injector;
};
/**
* Generate the documentation using the loaded packages
* @return {Promise} A promise to the generated documents
*/
Dgeni.prototype.generate = function () {
var _this = this;
var injector = this.configureInjector();
var log = injector.get('log');
var processingPromise = this.triggerEvent('generationStart');
// Process the docs
var currentDocs = [];
processingPromise = processingPromise.then(function () { return currentDocs; });
this.processors.forEach(function (processor) {
processingPromise = processingPromise.then(function (docs) { return _this.runProcessor(processor, docs); });
});
processingPromise.catch(function (error) {
log.error(error.message);
if (error.stack) {
log.debug(error.stack);
}
log.error('Failed to process the docs');
});
return processingPromise.then(function (docs) {
_this.triggerEvent('generationEnd');
return docs;
});
};
Dgeni.prototype.runProcessor = function (processor, docs) {
var _this = this;
var log = this.injector.get('log');
var promise = Promise.resolve(docs);
if (!processor.$process) {
return promise;
}
return promise
.then(function () {
log.info('running processor:', processor.name);
return _this.triggerProcessorEvent('processorStart', processor, docs);
})
// We need to wrap this $process call in a new promise handler so that we can catch
// errors triggered by exceptions thrown in the $process method
// before they reach the promise handlers
.then(function (docs) { return processor.$process(docs) || docs; })
.then(function (docs) { return _this.triggerProcessorEvent('processorEnd', processor, docs); })
.catch(function (error) {
error.message = 'Error running processor "' + processor.name + '":\n' + error.message;
if (_this.stopOnProcessingError) {
return Promise.reject(error);
}
else {
log.error(error.message);
}
return docs;
});
};
/**
* Trigger a dgeni event and run all the registered handlers
* All the arguments to this call are passed through to each handler
* @param {string} eventName The event being triggered
* @return {Promise} A promise to an array of the results from each of the handlers
*/
Dgeni.prototype.triggerEvent = function (eventName) {
var extras = [];
for (var _i = 1; _i < arguments.length; _i++) {
extras[_i - 1] = arguments[_i];
}
var handlers = this.handlerMap[eventName];
var handlersPromise = Promise.resolve();
var results = [];
if (handlers) {
handlers.forEach(function (handler) {
handlersPromise = handlersPromise.then(function () {
var handlerPromise = Promise.resolve(handler.apply(void 0, __spreadArrays([eventName], extras)));
handlerPromise.then(function (result) { return results.push(result); });
return handlerPromise;
});
});
}
return handlersPromise.then(function () { return results; });
};
Dgeni.prototype.triggerProcessorEvent = function (eventName, processor, docs) {
return this.triggerEvent(eventName, processor, docs).then(function () { return docs; });
};
Dgeni.prototype.info = function () {
var injector = this.configureInjector();
var log = injector.get('log');
for (var pkgName in this.packages) {
log.info(pkgName, '[' + this.packages[pkgName].dependencies.map(function (dep) { return JSON.stringify(dep.name); }).join(', ') + ']');
}
log.info('== Processors (processing order) ==');
this.processors.forEach(function (processor, index) {
log.info((index + 1) + ': ' + processor.name, processor.$process ? '' : '(abstract)', ' from ', processor.$package);
if (processor.description) {
log.info(' ', processor.description);
}
});
};
Dgeni.Package = Package_1.Package;
return Dgeni;
}());
exports.Dgeni = Dgeni;
//# sourceMappingURL=Dgeni.js.map