UNPKG

11.4 kBJavaScriptView Raw
1"use strict";
2var __spreadArrays = (this && this.__spreadArrays) || function () {
3 for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
4 for (var r = Array(s), k = 0, i = 0; i < il; i++)
5 for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
6 r[k] = a[j];
7 return r;
8};
9Object.defineProperty(exports, "__esModule", { value: true });
10exports.Dgeni = void 0;
11/* tslint globals: require: true */
12var di = require('di');
13var Package_1 = require("./Package");
14var processorValidation_1 = require("./legacyPackages/processorValidation");
15var dependency_sort_1 = require("./util/dependency-sort");
16var getInjectables_1 = require("./util/getInjectables");
17var log_1 = require("./util/log");
18/**
19 * Create an instance of the Dgeni documentation generator, loading any packages passed in as a
20 * parameter.
21 * @param {Package[]} [packages] A collection of packages to load
22 */
23var Dgeni = /** @class */ (function () {
24 function Dgeni(packages) {
25 var _this = this;
26 if (packages === void 0) { packages = []; }
27 this.packages = {};
28 if (!Array.isArray(packages)) {
29 throw new Error('packages must be an array');
30 }
31 // Add in the legacy validation that was originally part of the core Dgeni tool.
32 this.package(processorValidation_1.processorValidationPackage);
33 packages.map(function (p) { return _this.package(p); });
34 }
35 /**
36 * Load a package into dgeni
37 * @param package The package to load or the name of a new package to create.
38 * @param dependencies A collection of dependencies for this package
39 * @return The package that was loaded, to allow chaining
40 */
41 Dgeni.prototype.package = function (pkg, dependencies) {
42 var _this = this;
43 if (dependencies === void 0) { dependencies = []; }
44 if (this.injector) {
45 throw new Error('injector already configured - you cannot add a new package');
46 }
47 if (typeof pkg === 'string') {
48 pkg = new Package_1.Package(pkg, dependencies);
49 }
50 if (!(Package_1.Package.isPackage(pkg))) {
51 throw new Error('package must be an instance of Package');
52 }
53 if (this.packages[pkg.name]) {
54 throw new Error('The "' + pkg.name + '" package has already been loaded');
55 }
56 this.packages[pkg.name] = pkg;
57 // Extract all inline packages and load them into dgeni;
58 pkg.namedDependencies = pkg.dependencies.map(function (dependency) {
59 if (Package_1.Package.isPackage(dependency)) {
60 // Only load dependent package if not already loaded
61 if (!_this.packages[dependency.name]) {
62 _this.package(dependency);
63 }
64 return dependency.name;
65 }
66 return dependency;
67 });
68 // Return the package to allow chaining
69 return pkg;
70 };
71 /**
72 * Configure the injector using the loaded packages.
73 *
74 * The injector is assigned to the `injector` property on `this`, which is used by the
75 * `generate()` method. Subsequent calls to this method will just return the same injector.
76 *
77 * This method is useful in unit testing services and processors as it gives an easy way to
78 * get hold of an instance of a ready instantiated component without having to load in all
79 * the potential dependencies manually:
80 *
81 * ```
82 * const Dgeni = require('dgeni');
83 *
84 * function getInjector() {
85 * const dgeni = new Dgeni();
86 * dgeni.package('testPackage', [require('dgeni-packages/base')])
87 * .factory('templateEngine', function dummyTemplateEngine() {});
88 * return dgeni.configureInjector();
89 * };
90 *
91 * describe('someService', function() {
92 * const someService;
93 * beforeEach(function() {
94 * const injector = getInjector();
95 * someService = injector.get('someService');
96 * });
97 *
98 * it("should do something", function() {
99 * someService.doSomething();
100 * ...
101 * });
102 * });
103 * ```
104 */
105 Dgeni.prototype.configureInjector = function () {
106 var _this = this;
107 if (!this.injector) {
108 // Sort the packages by their dependency - ensures that services and configs are loaded in the
109 // correct order
110 var packages = this.packages = dependency_sort_1.sortByDependency(this.packages, 'namedDependencies');
111 // Create a module containing basic shared services
112 this.stopOnProcessingError = true;
113 var dgeniModule = new di.Module()
114 .value('dgeni', this)
115 .factory('log', log_1.logFactory)
116 .factory('getInjectables', getInjectables_1.getInjectablesFactory);
117 // Create the dependency injection container, from all the packages' modules
118 var modules = packages.map(function (pkg) { return pkg.module; });
119 modules.unshift(dgeniModule);
120 // Create the injector and
121 var injector_1 = this.injector = new di.Injector(modules);
122 // Apply the config blocks
123 packages.forEach(function (pkg) { return pkg.configFns.forEach(function (configFn) { return injector_1.invoke(configFn); }); });
124 // Get the the processors and event handlers
125 var processorMap_1 = {};
126 this.handlerMap = {};
127 packages.forEach(function (pkg) {
128 pkg.processors.forEach(function (processorName) {
129 var processor = injector_1.get(processorName);
130 // Update the processor's name and package
131 processor.name = processorName;
132 processor.$package = pkg.name;
133 // Ignore disabled processors
134 if (processor.$enabled !== false) {
135 processorMap_1[processorName] = processor;
136 }
137 });
138 var _loop_1 = function (eventName) {
139 var handlers = _this.handlerMap[eventName] = (_this.handlerMap[eventName] || []);
140 pkg.handlers[eventName].forEach(function (handlerName) { return handlers.push(injector_1.get(handlerName)); });
141 };
142 for (var eventName in pkg.handlers) {
143 _loop_1(eventName);
144 }
145 });
146 // Once we have configured everything sort the processors.
147 // This allows the config blocks to modify the $runBefore and $runAfter properties of processors.
148 // (Crazy idea, I know, but useful for things like debugDumpProcessor)
149 this.processors = dependency_sort_1.sortByDependency(processorMap_1, '$runAfter', '$runBefore');
150 }
151 return this.injector;
152 };
153 /**
154 * Generate the documentation using the loaded packages
155 * @return {Promise} A promise to the generated documents
156 */
157 Dgeni.prototype.generate = function () {
158 var _this = this;
159 var injector = this.configureInjector();
160 var log = injector.get('log');
161 var processingPromise = this.triggerEvent('generationStart');
162 // Process the docs
163 var currentDocs = [];
164 processingPromise = processingPromise.then(function () { return currentDocs; });
165 this.processors.forEach(function (processor) {
166 processingPromise = processingPromise.then(function (docs) { return _this.runProcessor(processor, docs); });
167 });
168 processingPromise.catch(function (error) {
169 log.error(error.message);
170 if (error.stack) {
171 log.debug(error.stack);
172 }
173 log.error('Failed to process the docs');
174 });
175 return processingPromise.then(function (docs) {
176 _this.triggerEvent('generationEnd');
177 return docs;
178 });
179 };
180 Dgeni.prototype.runProcessor = function (processor, docs) {
181 var _this = this;
182 var log = this.injector.get('log');
183 var promise = Promise.resolve(docs);
184 if (!processor.$process) {
185 return promise;
186 }
187 return promise
188 .then(function () {
189 log.info('running processor:', processor.name);
190 return _this.triggerProcessorEvent('processorStart', processor, docs);
191 })
192 // We need to wrap this $process call in a new promise handler so that we can catch
193 // errors triggered by exceptions thrown in the $process method
194 // before they reach the promise handlers
195 .then(function (docs) { return processor.$process(docs) || docs; })
196 .then(function (docs) { return _this.triggerProcessorEvent('processorEnd', processor, docs); })
197 .catch(function (error) {
198 error.message = 'Error running processor "' + processor.name + '":\n' + error.message;
199 if (_this.stopOnProcessingError) {
200 return Promise.reject(error);
201 }
202 else {
203 log.error(error.message);
204 }
205 return docs;
206 });
207 };
208 /**
209 * Trigger a dgeni event and run all the registered handlers
210 * All the arguments to this call are passed through to each handler
211 * @param {string} eventName The event being triggered
212 * @return {Promise} A promise to an array of the results from each of the handlers
213 */
214 Dgeni.prototype.triggerEvent = function (eventName) {
215 var extras = [];
216 for (var _i = 1; _i < arguments.length; _i++) {
217 extras[_i - 1] = arguments[_i];
218 }
219 var handlers = this.handlerMap[eventName];
220 var handlersPromise = Promise.resolve();
221 var results = [];
222 if (handlers) {
223 handlers.forEach(function (handler) {
224 handlersPromise = handlersPromise.then(function () {
225 var handlerPromise = Promise.resolve(handler.apply(void 0, __spreadArrays([eventName], extras)));
226 handlerPromise.then(function (result) { return results.push(result); });
227 return handlerPromise;
228 });
229 });
230 }
231 return handlersPromise.then(function () { return results; });
232 };
233 Dgeni.prototype.triggerProcessorEvent = function (eventName, processor, docs) {
234 return this.triggerEvent(eventName, processor, docs).then(function () { return docs; });
235 };
236 Dgeni.prototype.info = function () {
237 var injector = this.configureInjector();
238 var log = injector.get('log');
239 for (var pkgName in this.packages) {
240 log.info(pkgName, '[' + this.packages[pkgName].dependencies.map(function (dep) { return JSON.stringify(dep.name); }).join(', ') + ']');
241 }
242 log.info('== Processors (processing order) ==');
243 this.processors.forEach(function (processor, index) {
244 log.info((index + 1) + ': ' + processor.name, processor.$process ? '' : '(abstract)', ' from ', processor.$package);
245 if (processor.description) {
246 log.info(' ', processor.description);
247 }
248 });
249 };
250 Dgeni.Package = Package_1.Package;
251 return Dgeni;
252}());
253exports.Dgeni = Dgeni;
254//# sourceMappingURL=Dgeni.js.map
\No newline at end of file