/**
 * @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.io/license
 */
import { logging } from '@angular-devkit/core';
import { Observable } from 'rxjs';
import { Url } from 'url';
import { FileEntry, MergeStrategy, Tree } from '../tree/interface';
import { Workflow } from '../workflow/interface';
export interface TaskConfiguration<T = {}> {
    name: string;
    dependencies?: Array<TaskId>;
    options?: T;
}
export interface TaskConfigurationGenerator<T = {}> {
    toConfiguration(): TaskConfiguration<T>;
}
export type TaskExecutor<T = {}> = (options: T | undefined, context: SchematicContext) => Promise<void> | Observable<void>;
export interface TaskExecutorFactory<T> {
    readonly name: string;
    create(options?: T): Promise<TaskExecutor> | Observable<TaskExecutor>;
}
export interface TaskId {
    readonly id: number;
}
export interface TaskInfo {
    readonly id: number;
    readonly priority: number;
    readonly configuration: TaskConfiguration;
    readonly context: SchematicContext;
}
export interface ExecutionOptions {
    scope: string;
    interactive: boolean;
}
/**
 * The description (metadata) of a collection. This type contains every information the engine
 * needs to run. The CollectionMetadataT type parameter contains additional metadata that you
 * want to store while remaining type-safe.
 */
export type CollectionDescription<CollectionMetadataT extends object> = CollectionMetadataT & {
    readonly name: string;
    readonly extends?: string[];
};
/**
 * The description (metadata) of a schematic. This type contains every information the engine
 * needs to run. The SchematicMetadataT and CollectionMetadataT type parameters contain additional
 * metadata that you want to store while remaining type-safe.
 */
export type SchematicDescription<CollectionMetadataT extends object, SchematicMetadataT extends object> = SchematicMetadataT & {
    readonly collection: CollectionDescription<CollectionMetadataT>;
    readonly name: string;
    readonly private?: boolean;
    readonly hidden?: boolean;
};
/**
 * The Host for the Engine. Specifically, the piece of the tooling responsible for resolving
 * collections and schematics descriptions. The SchematicMetadataT and CollectionMetadataT type
 * parameters contain additional metadata that you want to store while remaining type-safe.
 */
export interface EngineHost<CollectionMetadataT extends object, SchematicMetadataT extends object> {
    createCollectionDescription(name: string, requester?: CollectionDescription<CollectionMetadataT>): CollectionDescription<CollectionMetadataT>;
    listSchematicNames(collection: CollectionDescription<CollectionMetadataT>, includeHidden?: boolean): string[];
    createSchematicDescription(name: string, collection: CollectionDescription<CollectionMetadataT>): SchematicDescription<CollectionMetadataT, SchematicMetadataT> | null;
    getSchematicRuleFactory<OptionT extends object>(schematic: SchematicDescription<CollectionMetadataT, SchematicMetadataT>, collection: CollectionDescription<CollectionMetadataT>): RuleFactory<OptionT>;
    createSourceFromUrl(url: Url, context: TypedSchematicContext<CollectionMetadataT, SchematicMetadataT>): Source | null;
    transformOptions<OptionT extends object, ResultT extends object>(schematic: SchematicDescription<CollectionMetadataT, SchematicMetadataT>, options: OptionT, context?: TypedSchematicContext<CollectionMetadataT, SchematicMetadataT>): Observable<ResultT>;
    transformContext(context: TypedSchematicContext<CollectionMetadataT, SchematicMetadataT>): TypedSchematicContext<CollectionMetadataT, SchematicMetadataT> | void;
    createTaskExecutor(name: string): Observable<TaskExecutor>;
    hasTaskExecutor(name: string): boolean;
    readonly defaultMergeStrategy?: MergeStrategy;
}
/**
 * The root Engine for creating and running schematics and collections. Everything related to
 * a schematic execution starts from this interface.
 *
 * CollectionMetadataT is, by default, a generic Collection metadata type. This is used throughout
 * the engine typings so that you can use a type that's merged into descriptions, while being
 * type-safe.
 *
 * SchematicMetadataT is a type that contains additional typing for the Schematic Description.
 */
export interface Engine<CollectionMetadataT extends object, SchematicMetadataT extends object> {
    createCollection(name: string, requester?: Collection<CollectionMetadataT, SchematicMetadataT>): Collection<CollectionMetadataT, SchematicMetadataT>;
    createContext(schematic: Schematic<CollectionMetadataT, SchematicMetadataT>, parent?: Partial<TypedSchematicContext<CollectionMetadataT, SchematicMetadataT>>, executionOptions?: Partial<ExecutionOptions>): TypedSchematicContext<CollectionMetadataT, SchematicMetadataT>;
    createSchematic(name: string, collection: Collection<CollectionMetadataT, SchematicMetadataT>): Schematic<CollectionMetadataT, SchematicMetadataT>;
    createSourceFromUrl(url: Url, context: TypedSchematicContext<CollectionMetadataT, SchematicMetadataT>): Source;
    transformOptions<OptionT extends object, ResultT extends object>(schematic: Schematic<CollectionMetadataT, SchematicMetadataT>, options: OptionT, context?: TypedSchematicContext<CollectionMetadataT, SchematicMetadataT>): Observable<ResultT>;
    executePostTasks(): Observable<void>;
    readonly defaultMergeStrategy: MergeStrategy;
    readonly workflow: Workflow | null;
}
/**
 * A Collection as created by the Engine. This should be used by the tool to create schematics,
 * or by rules to create other schematics as well.
 */
export interface Collection<CollectionMetadataT extends object, SchematicMetadataT extends object> {
    readonly description: CollectionDescription<CollectionMetadataT>;
    readonly baseDescriptions?: Array<CollectionDescription<CollectionMetadataT>>;
    createSchematic(name: string, allowPrivate?: boolean): Schematic<CollectionMetadataT, SchematicMetadataT>;
    listSchematicNames(includeHidden?: boolean): string[];
}
/**
 * A Schematic as created by the Engine. This should be used by the tool to execute the main
 * schematics, or by rules to execute other schematics as well.
 */
export interface Schematic<CollectionMetadataT extends object, SchematicMetadataT extends object> {
    readonly description: SchematicDescription<CollectionMetadataT, SchematicMetadataT>;
    readonly collection: Collection<CollectionMetadataT, SchematicMetadataT>;
    call<OptionT extends object>(options: OptionT, host: Observable<Tree>, parentContext?: Partial<TypedSchematicContext<CollectionMetadataT, SchematicMetadataT>>, executionOptions?: Partial<ExecutionOptions>): Observable<Tree>;
}
/**
 * A SchematicContext. Contains information necessary for Schematics to execute some rules, for
 * example when using another schematics, as we need the engine and collection.
 */
export interface TypedSchematicContext<CollectionMetadataT extends object, SchematicMetadataT extends object> {
    readonly debug: boolean;
    readonly engine: Engine<CollectionMetadataT, SchematicMetadataT>;
    readonly logger: logging.LoggerApi;
    readonly schematic: Schematic<CollectionMetadataT, SchematicMetadataT>;
    readonly strategy: MergeStrategy;
    readonly interactive: boolean;
    addTask<T extends object>(task: TaskConfigurationGenerator<T>, dependencies?: Array<TaskId>): TaskId;
}
/**
 * This is used by the Schematics implementations in order to avoid needing to have typing from
 * the tooling. Schematics are not specific to a tool.
 */
export type SchematicContext = TypedSchematicContext<{}, {}>;
/**
 * A rule factory, which is normally the way schematics are implemented. Returned by the tooling
 * after loading a schematic description.
 */
export type RuleFactory<T extends object> = (options: T) => Rule;
/**
 * A FileOperator applies changes synchronously to a FileEntry. An async operator returns
 * asynchronously. We separate them so that the type system can catch early errors.
 */
export type FileOperator = (entry: FileEntry) => FileEntry | null;
export type AsyncFileOperator = (tree: FileEntry) => Observable<FileEntry | null>;
/**
 * A source is a function that generates a Tree from a specific context. A rule transforms a tree
 * into another tree from a specific context. In both cases, an Observable can be returned if
 * the source or the rule are asynchronous. Only the last Tree generated in the observable will
 * be used though.
 *
 * We obfuscate the context of Source and Rule because the schematic implementation should not
 * know which types is the schematic or collection metadata, as they are both tooling specific.
 */
export type Source = (context: SchematicContext) => Tree | Observable<Tree>;
export type Rule = (tree: Tree, context: SchematicContext) => Tree | Observable<Tree> | Rule | Promise<void | Rule> | void;
