UNPKG

@angular-devkit/architect

Version:
184 lines (183 loc) 8.82 kB
"use strict"; /** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ Object.defineProperty(exports, "__esModule", { value: true }); exports.createBuilder = createBuilder; const core_1 = require("@angular-devkit/core"); const rxjs_1 = require("rxjs"); const api_1 = require("./api"); const internal_1 = require("./internal"); const jobs_1 = require("./jobs"); const schedule_by_name_1 = require("./schedule-by-name"); // eslint-disable-next-line max-lines-per-function function createBuilder(fn) { const cjh = jobs_1.createJobHandler; // eslint-disable-next-line max-lines-per-function const handler = cjh((options, context) => { const scheduler = context.scheduler; const progressChannel = context.createChannel('progress'); const logChannel = context.createChannel('log'); const addTeardown = context.addTeardown.bind(context); let currentState = api_1.BuilderProgressState.Stopped; let current = 0; let status = ''; let total = 1; function log(entry) { logChannel.next(entry); } function progress(progress, context) { currentState = progress.state; if (progress.state === api_1.BuilderProgressState.Running) { current = progress.current; total = progress.total !== undefined ? progress.total : total; if (progress.status === undefined) { progress.status = status; } else { status = progress.status; } } progressChannel.next({ ...progress, ...(context.target && { target: context.target }), ...(context.builder && { builder: context.builder }), id: context.id, }); } return new rxjs_1.Observable((observer) => { const subscriptions = []; const inputSubscription = context.inboundBus.subscribe((i) => { switch (i.kind) { case jobs_1.JobInboundMessageKind.Input: onInput(i.value); break; } }); function onInput(i) { const builder = i.info; const loggerName = i.target ? (0, api_1.targetStringFromTarget)(i.target) : builder.builderName; const logger = new core_1.logging.Logger(loggerName); subscriptions.push(logger.subscribe((entry) => log(entry))); const context = { builder, workspaceRoot: i.workspaceRoot, currentDirectory: i.currentDirectory, target: i.target, logger: logger, id: i.id, async scheduleTarget(target, overrides = {}, scheduleOptions = {}) { const run = await (0, schedule_by_name_1.scheduleByTarget)(target, overrides, { scheduler, logger: scheduleOptions.logger || logger.createChild(''), workspaceRoot: i.workspaceRoot, currentDirectory: i.currentDirectory, }); // We don't want to subscribe errors and complete. subscriptions.push(run.progress.subscribe((event) => progressChannel.next(event))); return run; }, async scheduleBuilder(builderName, options = {}, scheduleOptions = {}) { const run = await (0, schedule_by_name_1.scheduleByName)(builderName, options, { scheduler, target: scheduleOptions.target, logger: scheduleOptions.logger || logger.createChild(''), workspaceRoot: i.workspaceRoot, currentDirectory: i.currentDirectory, }); // We don't want to subscribe errors and complete. subscriptions.push(run.progress.subscribe((event) => progressChannel.next(event))); return run; }, async getTargetOptions(target) { return (0, rxjs_1.firstValueFrom)(scheduler.schedule('..getTargetOptions', target).output); }, async getProjectMetadata(target) { return (0, rxjs_1.firstValueFrom)(scheduler.schedule('..getProjectMetadata', target).output); }, async getBuilderNameForTarget(target) { return (0, rxjs_1.firstValueFrom)(scheduler.schedule('..getBuilderNameForTarget', target).output); }, async validateOptions(options, builderName) { return (0, rxjs_1.firstValueFrom)(scheduler.schedule('..validateOptions', [builderName, options]).output); }, reportRunning() { switch (currentState) { case api_1.BuilderProgressState.Waiting: case api_1.BuilderProgressState.Stopped: progress({ state: api_1.BuilderProgressState.Running, current: 0, total }, context); break; } }, reportStatus(status) { switch (currentState) { case api_1.BuilderProgressState.Running: progress({ state: currentState, status, current, total }, context); break; case api_1.BuilderProgressState.Waiting: progress({ state: currentState, status }, context); break; } }, reportProgress(current, total, status) { switch (currentState) { case api_1.BuilderProgressState.Running: progress({ state: currentState, current, total, status }, context); } }, addTeardown, }; context.reportRunning(); let result; try { result = fn(i.options, context); if ((0, api_1.isBuilderOutput)(result)) { result = (0, rxjs_1.of)(result); } else if (!(0, rxjs_1.isObservable)(result) && isAsyncIterable(result)) { result = (0, api_1.fromAsyncIterable)(result); } else { result = (0, rxjs_1.from)(result); } } catch (e) { result = (0, rxjs_1.throwError)(e); } // Manage some state automatically. progress({ state: api_1.BuilderProgressState.Running, current: 0, total: 1 }, context); subscriptions.push(result .pipe((0, rxjs_1.defaultIfEmpty)({ success: false }), (0, rxjs_1.tap)(() => { progress({ state: api_1.BuilderProgressState.Running, current: total }, context); progress({ state: api_1.BuilderProgressState.Stopped }, context); }), (0, rxjs_1.mergeMap)(async (value) => { // Allow the log queue to flush await new Promise(setImmediate); return value; })) .subscribe((message) => observer.next(message), (error) => observer.error(error), () => observer.complete())); } return () => { subscriptions.forEach((x) => x.unsubscribe()); inputSubscription.unsubscribe(); }; }); }); return { handler, [internal_1.BuilderSymbol]: true, [internal_1.BuilderVersionSymbol]: require('../package.json').version, // Only needed for type safety around `Builder` types. // eslint-disable-next-line @typescript-eslint/no-non-null-assertion __OptionT: null, }; } function isAsyncIterable(obj) { return !!obj && typeof obj[Symbol.asyncIterator] === 'function'; }