UNPKG

5.79 kBJavaScriptView Raw
1"use strict";
2/**
3 * @license
4 * Copyright Google LLC All Rights Reserved.
5 *
6 * Use of this source code is governed by an MIT-style license that can be
7 * found in the LICENSE file at https://angular.io/license
8 */
9Object.defineProperty(exports, "__esModule", { value: true });
10exports.BaseWorkflow = void 0;
11const core_1 = require("@angular-devkit/core");
12const rxjs_1 = require("rxjs");
13const operators_1 = require("rxjs/operators");
14const engine_1 = require("../engine");
15const exception_1 = require("../exception/exception");
16const formats_1 = require("../formats");
17const dryrun_1 = require("../sink/dryrun");
18const host_1 = require("../sink/host");
19const host_tree_1 = require("../tree/host-tree");
20/**
21 * Base class for workflows. Even without abstract methods, this class should not be used without
22 * surrounding some initialization for the registry and host. This class only adds life cycle and
23 * dryrun/force support. You need to provide any registry and task executors that you need to
24 * support.
25 * See {@see NodeWorkflow} implementation for how to make a specialized subclass of this.
26 * TODO: add default set of CoreSchemaRegistry transforms. Once the job refactor is done, use that
27 * as the support for tasks.
28 *
29 * @public
30 */
31class BaseWorkflow {
32 constructor(options) {
33 this._reporter = new rxjs_1.Subject();
34 this._lifeCycle = new rxjs_1.Subject();
35 this._host = options.host;
36 this._engineHost = options.engineHost;
37 if (options.registry) {
38 this._registry = options.registry;
39 }
40 else {
41 this._registry = new core_1.schema.CoreSchemaRegistry(formats_1.standardFormats);
42 this._registry.addPostTransform(core_1.schema.transforms.addUndefinedDefaults);
43 }
44 this._engine = new engine_1.SchematicEngine(this._engineHost, this);
45 this._context = [];
46 this._force = options.force || false;
47 this._dryRun = options.dryRun || false;
48 }
49 get context() {
50 const maybeContext = this._context[this._context.length - 1];
51 if (!maybeContext) {
52 throw new Error('Cannot get context when workflow is not executing...');
53 }
54 return maybeContext;
55 }
56 get engine() {
57 return this._engine;
58 }
59 get engineHost() {
60 return this._engineHost;
61 }
62 get registry() {
63 return this._registry;
64 }
65 get reporter() {
66 return this._reporter.asObservable();
67 }
68 get lifeCycle() {
69 return this._lifeCycle.asObservable();
70 }
71 _createSinks() {
72 let error = false;
73 const dryRunSink = new dryrun_1.DryRunSink(this._host, this._force);
74 const dryRunSubscriber = dryRunSink.reporter.subscribe((event) => {
75 this._reporter.next(event);
76 error = error || event.kind == 'error';
77 });
78 // We need two sinks if we want to output what will happen, and actually do the work.
79 return [
80 dryRunSink,
81 // Add a custom sink that clean ourselves and throws an error if an error happened.
82 {
83 commit() {
84 dryRunSubscriber.unsubscribe();
85 if (error) {
86 return (0, rxjs_1.throwError)(new exception_1.UnsuccessfulWorkflowExecution());
87 }
88 return (0, rxjs_1.of)();
89 },
90 },
91 // Only add a HostSink if this is not a dryRun.
92 ...(!this._dryRun ? [new host_1.HostSink(this._host, this._force)] : []),
93 ];
94 }
95 execute(options) {
96 const parentContext = this._context[this._context.length - 1];
97 if (!parentContext) {
98 this._lifeCycle.next({ kind: 'start' });
99 }
100 /** Create the collection and the schematic. */
101 const collection = this._engine.createCollection(options.collection);
102 // Only allow private schematics if called from the same collection.
103 const allowPrivate = options.allowPrivate || (parentContext && parentContext.collection === options.collection);
104 const schematic = collection.createSchematic(options.schematic, allowPrivate);
105 const sinks = this._createSinks();
106 this._lifeCycle.next({ kind: 'workflow-start' });
107 const context = {
108 ...options,
109 debug: options.debug || false,
110 logger: options.logger || (parentContext && parentContext.logger) || new core_1.logging.NullLogger(),
111 parentContext,
112 };
113 this._context.push(context);
114 return schematic
115 .call(options.options, (0, rxjs_1.of)(new host_tree_1.HostTree(this._host)), { logger: context.logger })
116 .pipe((0, operators_1.concatMap)((tree) => {
117 // Process all sinks.
118 return (0, rxjs_1.concat)((0, rxjs_1.from)(sinks).pipe((0, operators_1.concatMap)((sink) => sink.commit(tree)), (0, operators_1.ignoreElements)()), (0, rxjs_1.of)(tree));
119 }), (0, operators_1.concatMap)(() => {
120 if (this._dryRun) {
121 return rxjs_1.EMPTY;
122 }
123 this._lifeCycle.next({ kind: 'post-tasks-start' });
124 return this._engine
125 .executePostTasks()
126 .pipe((0, operators_1.tap)({ complete: () => this._lifeCycle.next({ kind: 'post-tasks-end' }) }), (0, operators_1.defaultIfEmpty)(), (0, operators_1.last)());
127 }), (0, operators_1.tap)({
128 complete: () => {
129 this._lifeCycle.next({ kind: 'workflow-end' });
130 this._context.pop();
131 if (this._context.length == 0) {
132 this._lifeCycle.next({ kind: 'end' });
133 }
134 },
135 }));
136 }
137}
138exports.BaseWorkflow = BaseWorkflow;