1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 | Object.defineProperty(exports, "__esModule", { value: true });
|
10 | exports.Architect = void 0;
|
11 | const core_1 = require("@angular-devkit/core");
|
12 | const rxjs_1 = require("rxjs");
|
13 | const operators_1 = require("rxjs/operators");
|
14 | const api_1 = require("./api");
|
15 | const jobs_1 = require("./jobs");
|
16 | const schedule_by_name_1 = require("./schedule-by-name");
|
17 | const inputSchema = require('./input-schema.json');
|
18 | const outputSchema = require('./output-schema.json');
|
19 | function _createJobHandlerFromBuilderInfo(info, target, host, registry, baseOptions) {
|
20 | const jobDescription = {
|
21 | name: target ? `{${(0, api_1.targetStringFromTarget)(target)}}` : info.builderName,
|
22 | argument: { type: 'object' },
|
23 | input: inputSchema,
|
24 | output: outputSchema,
|
25 | info,
|
26 | };
|
27 | function handler(argument, context) {
|
28 |
|
29 | const inboundBusWithInputValidation = context.inboundBus.pipe((0, operators_1.concatMap)((message) => {
|
30 | if (message.kind === jobs_1.JobInboundMessageKind.Input) {
|
31 | const v = message.value;
|
32 | const options = {
|
33 | ...baseOptions,
|
34 | ...v.options,
|
35 | };
|
36 |
|
37 | return registry.compile(info.optionSchema).pipe((0, operators_1.concatMap)((validation) => validation(options)), (0, operators_1.map)((validationResult) => {
|
38 | const { data, success, errors } = validationResult;
|
39 | if (success) {
|
40 | return { ...v, options: data };
|
41 | }
|
42 | throw new core_1.json.schema.SchemaValidationException(errors);
|
43 | }), (0, operators_1.map)((value) => ({ ...message, value })));
|
44 | }
|
45 | else {
|
46 | return (0, rxjs_1.of)(message);
|
47 | }
|
48 | }),
|
49 |
|
50 |
|
51 | (0, operators_1.shareReplay)(1));
|
52 |
|
53 |
|
54 | const inboundBus = (0, rxjs_1.onErrorResumeNext)(inboundBusWithInputValidation);
|
55 | const output = (0, rxjs_1.from)(host.loadBuilder(info)).pipe((0, operators_1.concatMap)((builder) => {
|
56 | if (builder === null) {
|
57 | throw new Error(`Cannot load builder for builderInfo ${JSON.stringify(info, null, 2)}`);
|
58 | }
|
59 | return builder.handler(argument, { ...context, inboundBus }).pipe((0, operators_1.map)((output) => {
|
60 | if (output.kind === jobs_1.JobOutboundMessageKind.Output) {
|
61 |
|
62 | return {
|
63 | ...output,
|
64 | value: {
|
65 | ...output.value,
|
66 | ...(target ? { target } : 0),
|
67 | },
|
68 | };
|
69 | }
|
70 | else {
|
71 | return output;
|
72 | }
|
73 | }));
|
74 | }),
|
75 |
|
76 | (0, operators_1.shareReplay)());
|
77 |
|
78 |
|
79 | const inboundBusErrors = inboundBusWithInputValidation.pipe((0, operators_1.ignoreElements)(), (0, operators_1.takeUntil)((0, rxjs_1.onErrorResumeNext)(output.pipe((0, operators_1.last)()))));
|
80 |
|
81 | return (0, rxjs_1.merge)(inboundBusErrors, output);
|
82 | }
|
83 | return (0, rxjs_1.of)(Object.assign(handler, { jobDescription }));
|
84 | }
|
85 |
|
86 |
|
87 |
|
88 | class ArchitectBuilderJobRegistry {
|
89 | constructor(_host, _registry, _jobCache, _infoCache) {
|
90 | this._host = _host;
|
91 | this._registry = _registry;
|
92 | this._jobCache = _jobCache;
|
93 | this._infoCache = _infoCache;
|
94 | }
|
95 | _resolveBuilder(name) {
|
96 | const cache = this._infoCache;
|
97 | if (cache) {
|
98 | const maybeCache = cache.get(name);
|
99 | if (maybeCache !== undefined) {
|
100 | return maybeCache;
|
101 | }
|
102 | const info = (0, rxjs_1.from)(this._host.resolveBuilder(name)).pipe((0, operators_1.shareReplay)(1));
|
103 | cache.set(name, info);
|
104 | return info;
|
105 | }
|
106 | return (0, rxjs_1.from)(this._host.resolveBuilder(name));
|
107 | }
|
108 | _createBuilder(info, target, options) {
|
109 | const cache = this._jobCache;
|
110 | if (target) {
|
111 | const maybeHit = cache && cache.get((0, api_1.targetStringFromTarget)(target));
|
112 | if (maybeHit) {
|
113 | return maybeHit;
|
114 | }
|
115 | }
|
116 | else {
|
117 | const maybeHit = cache && cache.get(info.builderName);
|
118 | if (maybeHit) {
|
119 | return maybeHit;
|
120 | }
|
121 | }
|
122 | const result = _createJobHandlerFromBuilderInfo(info, target, this._host, this._registry, options || {});
|
123 | if (cache) {
|
124 | if (target) {
|
125 | cache.set((0, api_1.targetStringFromTarget)(target), result.pipe((0, operators_1.shareReplay)(1)));
|
126 | }
|
127 | else {
|
128 | cache.set(info.builderName, result.pipe((0, operators_1.shareReplay)(1)));
|
129 | }
|
130 | }
|
131 | return result;
|
132 | }
|
133 | get(name) {
|
134 | const m = name.match(/^([^:]+):([^:]+)$/i);
|
135 | if (!m) {
|
136 | return (0, rxjs_1.of)(null);
|
137 | }
|
138 | return (0, rxjs_1.from)(this._resolveBuilder(name)).pipe((0, operators_1.concatMap)((builderInfo) => (builderInfo ? this._createBuilder(builderInfo) : (0, rxjs_1.of)(null))), (0, operators_1.first)(null, null));
|
139 | }
|
140 | }
|
141 |
|
142 |
|
143 |
|
144 | class ArchitectTargetJobRegistry extends ArchitectBuilderJobRegistry {
|
145 | get(name) {
|
146 | const m = name.match(/^{([^:]+):([^:]+)(?::([^:]*))?}$/i);
|
147 | if (!m) {
|
148 | return (0, rxjs_1.of)(null);
|
149 | }
|
150 | const target = {
|
151 | project: m[1],
|
152 | target: m[2],
|
153 | configuration: m[3],
|
154 | };
|
155 | return (0, rxjs_1.from)(Promise.all([
|
156 | this._host.getBuilderNameForTarget(target),
|
157 | this._host.getOptionsForTarget(target),
|
158 | ])).pipe((0, operators_1.concatMap)(([builderStr, options]) => {
|
159 | if (builderStr === null || options === null) {
|
160 | return (0, rxjs_1.of)(null);
|
161 | }
|
162 | return this._resolveBuilder(builderStr).pipe((0, operators_1.concatMap)((builderInfo) => {
|
163 | if (builderInfo === null) {
|
164 | return (0, rxjs_1.of)(null);
|
165 | }
|
166 | return this._createBuilder(builderInfo, target, options);
|
167 | }));
|
168 | }), (0, operators_1.first)(null, null));
|
169 | }
|
170 | }
|
171 | function _getTargetOptionsFactory(host) {
|
172 | return (0, jobs_1.createJobHandler)((target) => {
|
173 | return host.getOptionsForTarget(target).then((options) => {
|
174 | if (options === null) {
|
175 | throw new Error(`Invalid target: ${JSON.stringify(target)}.`);
|
176 | }
|
177 | return options;
|
178 | });
|
179 | }, {
|
180 | name: '..getTargetOptions',
|
181 | output: { type: 'object' },
|
182 | argument: inputSchema.properties.target,
|
183 | });
|
184 | }
|
185 | function _getProjectMetadataFactory(host) {
|
186 | return (0, jobs_1.createJobHandler)((target) => {
|
187 | return host.getProjectMetadata(target).then((options) => {
|
188 | if (options === null) {
|
189 | throw new Error(`Invalid target: ${JSON.stringify(target)}.`);
|
190 | }
|
191 | return options;
|
192 | });
|
193 | }, {
|
194 | name: '..getProjectMetadata',
|
195 | output: { type: 'object' },
|
196 | argument: {
|
197 | oneOf: [{ type: 'string' }, inputSchema.properties.target],
|
198 | },
|
199 | });
|
200 | }
|
201 | function _getBuilderNameForTargetFactory(host) {
|
202 | return (0, jobs_1.createJobHandler)(async (target) => {
|
203 | const builderName = await host.getBuilderNameForTarget(target);
|
204 | if (!builderName) {
|
205 | throw new Error(`No builder were found for target ${(0, api_1.targetStringFromTarget)(target)}.`);
|
206 | }
|
207 | return builderName;
|
208 | }, {
|
209 | name: '..getBuilderNameForTarget',
|
210 | output: { type: 'string' },
|
211 | argument: inputSchema.properties.target,
|
212 | });
|
213 | }
|
214 | function _validateOptionsFactory(host, registry) {
|
215 | return (0, jobs_1.createJobHandler)(async ([builderName, options]) => {
|
216 |
|
217 | const builderInfo = await host.resolveBuilder(builderName);
|
218 | if (!builderInfo) {
|
219 | throw new Error(`No builder info were found for builder ${JSON.stringify(builderName)}.`);
|
220 | }
|
221 | return registry
|
222 | .compile(builderInfo.optionSchema)
|
223 | .pipe((0, operators_1.concatMap)((validation) => validation(options)), (0, operators_1.switchMap)(({ data, success, errors }) => {
|
224 | if (success) {
|
225 | return (0, rxjs_1.of)(data);
|
226 | }
|
227 | throw new core_1.json.schema.SchemaValidationException(errors);
|
228 | }))
|
229 | .toPromise();
|
230 | }, {
|
231 | name: '..validateOptions',
|
232 | output: { type: 'object' },
|
233 | argument: {
|
234 | type: 'array',
|
235 | items: [{ type: 'string' }, { type: 'object' }],
|
236 | },
|
237 | });
|
238 | }
|
239 | class Architect {
|
240 | constructor(_host, registry = new core_1.json.schema.CoreSchemaRegistry(), additionalJobRegistry) {
|
241 | this._host = _host;
|
242 | this._jobCache = new Map();
|
243 | this._infoCache = new Map();
|
244 | const privateArchitectJobRegistry = new jobs_1.SimpleJobRegistry();
|
245 |
|
246 | privateArchitectJobRegistry.register(_getTargetOptionsFactory(_host));
|
247 | privateArchitectJobRegistry.register(_getBuilderNameForTargetFactory(_host));
|
248 | privateArchitectJobRegistry.register(_validateOptionsFactory(_host, registry));
|
249 | privateArchitectJobRegistry.register(_getProjectMetadataFactory(_host));
|
250 | const jobRegistry = new jobs_1.FallbackRegistry([
|
251 | new ArchitectTargetJobRegistry(_host, registry, this._jobCache, this._infoCache),
|
252 | new ArchitectBuilderJobRegistry(_host, registry, this._jobCache, this._infoCache),
|
253 | privateArchitectJobRegistry,
|
254 | ...(additionalJobRegistry ? [additionalJobRegistry] : []),
|
255 | ]);
|
256 | this._scheduler = new jobs_1.SimpleScheduler(jobRegistry, registry);
|
257 | }
|
258 | has(name) {
|
259 | return this._scheduler.has(name);
|
260 | }
|
261 | scheduleBuilder(name, options, scheduleOptions = {}) {
|
262 |
|
263 | if (!/^[^:]+:[^:]+(:[^:]+)?$/.test(name)) {
|
264 | throw new Error('Invalid builder name: ' + JSON.stringify(name));
|
265 | }
|
266 | return (0, schedule_by_name_1.scheduleByName)(name, options, {
|
267 | scheduler: this._scheduler,
|
268 | logger: scheduleOptions.logger || new core_1.logging.NullLogger(),
|
269 | currentDirectory: this._host.getCurrentDirectory(),
|
270 | workspaceRoot: this._host.getWorkspaceRoot(),
|
271 | });
|
272 | }
|
273 | scheduleTarget(target, overrides = {}, scheduleOptions = {}) {
|
274 | return (0, schedule_by_name_1.scheduleByTarget)(target, overrides, {
|
275 | scheduler: this._scheduler,
|
276 | logger: scheduleOptions.logger || new core_1.logging.NullLogger(),
|
277 | currentDirectory: this._host.getCurrentDirectory(),
|
278 | workspaceRoot: this._host.getWorkspaceRoot(),
|
279 | });
|
280 | }
|
281 | }
|
282 | exports.Architect = Architect;
|