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