mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-18 11:44:05 +08:00
This change first attempts to resolve a schematic referenced via the external schematic rule from the requesting schematic collection. This allows schematic packages that are direct dependencies of another schematic package to be used with the external schematic rule without manual package resolution code within the schematic. Closes #18098 Closes #11026
143 lines
4.2 KiB
TypeScript
143 lines
4.2 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google Inc. 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.io/license
|
|
*/
|
|
import { Observable, of as observableOf, throwError } from 'rxjs';
|
|
import { mergeMap } from 'rxjs/operators';
|
|
import { Url } from 'url';
|
|
import {
|
|
CollectionDescription,
|
|
EngineHost,
|
|
RuleFactory,
|
|
SchematicDescription,
|
|
Source,
|
|
TaskExecutor,
|
|
TypedSchematicContext,
|
|
UnknownCollectionException,
|
|
UnregisteredTaskException,
|
|
} from '../src';
|
|
|
|
|
|
export type FallbackCollectionDescription = {
|
|
host: EngineHost<{}, {}>;
|
|
description: CollectionDescription<{}>;
|
|
};
|
|
export type FallbackSchematicDescription = {
|
|
description: SchematicDescription<{}, {}>;
|
|
};
|
|
export type FallbackContext =
|
|
TypedSchematicContext<FallbackCollectionDescription, FallbackSchematicDescription>;
|
|
|
|
|
|
/**
|
|
* An EngineHost that support multiple hosts in a fallback configuration. If a host does not
|
|
* have a collection/schematics, use the following host before giving up.
|
|
*/
|
|
export class FallbackEngineHost implements EngineHost<{}, {}> {
|
|
private _hosts: EngineHost<{}, {}>[] = [];
|
|
|
|
constructor() {}
|
|
|
|
addHost<CollectionT extends object, SchematicT extends object>(
|
|
host: EngineHost<CollectionT, SchematicT>,
|
|
) {
|
|
this._hosts.push(host);
|
|
}
|
|
|
|
createCollectionDescription(name: string, requester?: CollectionDescription<{}>): CollectionDescription<FallbackCollectionDescription> {
|
|
for (const host of this._hosts) {
|
|
try {
|
|
const description = host.createCollectionDescription(name, requester);
|
|
|
|
return { name, host, description };
|
|
} catch (_) {
|
|
}
|
|
}
|
|
|
|
throw new UnknownCollectionException(name);
|
|
}
|
|
|
|
createSchematicDescription(
|
|
name: string,
|
|
collection: CollectionDescription<FallbackCollectionDescription>,
|
|
): SchematicDescription<FallbackCollectionDescription, FallbackSchematicDescription> | null {
|
|
const description = collection.host.createSchematicDescription(name, collection.description);
|
|
if (!description) {
|
|
return null;
|
|
}
|
|
|
|
return { name, collection, description };
|
|
}
|
|
|
|
getSchematicRuleFactory<OptionT extends object>(
|
|
schematic: SchematicDescription<FallbackCollectionDescription, FallbackSchematicDescription>,
|
|
collection: CollectionDescription<FallbackCollectionDescription>): RuleFactory<OptionT> {
|
|
return collection.host.getSchematicRuleFactory(schematic.description, collection.description);
|
|
}
|
|
|
|
createSourceFromUrl(
|
|
url: Url,
|
|
context: FallbackContext,
|
|
): Source | null {
|
|
return context.schematic.collection.description.host.createSourceFromUrl(url, context);
|
|
}
|
|
|
|
transformOptions<OptionT extends object, ResultT extends object>(
|
|
schematic: SchematicDescription<FallbackCollectionDescription, FallbackSchematicDescription>,
|
|
options: OptionT,
|
|
context?: FallbackContext,
|
|
): Observable<ResultT> {
|
|
// tslint:disable-next-line:no-any https://github.com/ReactiveX/rxjs/issues/3989
|
|
return ((observableOf(options) as any)
|
|
.pipe(...this._hosts
|
|
.map(host => mergeMap((opt: {}) => host.transformOptions(schematic, opt, context))),
|
|
)
|
|
) as {} as Observable<ResultT>;
|
|
}
|
|
|
|
transformContext(context: FallbackContext): FallbackContext {
|
|
let result = context;
|
|
|
|
this._hosts.forEach(host => {
|
|
result = (host.transformContext(result) || result) as FallbackContext;
|
|
});
|
|
|
|
return result;
|
|
}
|
|
|
|
listSchematicNames(collection: CollectionDescription<FallbackCollectionDescription>): string[] {
|
|
const allNames = new Set<string>();
|
|
this._hosts.forEach(host => {
|
|
try {
|
|
host.listSchematicNames(collection.description).forEach(name => allNames.add(name));
|
|
} catch (_) {}
|
|
});
|
|
|
|
return [...allNames];
|
|
}
|
|
|
|
createTaskExecutor(name: string): Observable<TaskExecutor> {
|
|
for (const host of this._hosts) {
|
|
if (host.hasTaskExecutor(name)) {
|
|
return host.createTaskExecutor(name);
|
|
}
|
|
}
|
|
|
|
return throwError(new UnregisteredTaskException(name));
|
|
}
|
|
|
|
hasTaskExecutor(name: string): boolean {
|
|
for (const host of this._hosts) {
|
|
if (host.hasTaskExecutor(name)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|