or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

file-system-actions.mdindex.mdnode-tools.mdoutput-sinks.mdrule-system.mdschematic-engine.mdtemplate-engine.mdtree-operations.mdworkflow.md
tile.json

schematic-engine.mddocs/

Schematic Engine

Execution engine for running schematics with metadata, collections, and workflow orchestration. The engine handles schematic discovery, validation, execution, and task management in a structured, pluggable way.

Capabilities

Engine Interface

The main engine interface for orchestrating schematic execution.

/**
 * Root interface for creating and running schematics and collections
 */
interface Engine<CollectionMetadataT, SchematicMetadataT> {
  readonly defaultMergeStrategy: MergeStrategy;
  readonly workflow: Workflow | null;
  
  /** Create a collection from name and optional requester */
  createCollection(
    name: string, 
    requester?: Collection<CollectionMetadataT, SchematicMetadataT>
  ): Collection<CollectionMetadataT, SchematicMetadataT>;
  
  /** Create execution context for a schematic */
  createContext(
    schematic: Schematic<CollectionMetadataT, SchematicMetadataT>,
    parent?: Readonly<SchematicContext>,
    executionOptions?: Partial<ExecutionOptions>
  ): SchematicContext;
  
  /** Create a schematic from collection */
  createSchematic(
    name: string,
    collection: Collection<CollectionMetadataT, SchematicMetadataT>
  ): Schematic<CollectionMetadataT, SchematicMetadataT>;
  
  /** Create source from URL */
  createSourceFromUrl(url: Url, context: SchematicContext): Source;
  
  /** Transform options using schematic metadata */
  transformOptions<OptionT, ResultT>(
    schematic: Schematic<CollectionMetadataT, SchematicMetadataT>,
    options: OptionT,
    context?: SchematicContext
  ): Observable<ResultT>;
  
  /** Execute post-schematic tasks */
  executePostTasks(): Observable<void>;
}

Engine Host

Interface for resolving and providing schematic resources.

/**
 * Host interface for resolving collections and schematics
 */
interface EngineHost<CollectionMetadataT, SchematicMetadataT> {
  /** Create collection description with metadata */
  createCollectionDescription(
    name: string,
    requester?: CollectionDescription<CollectionMetadataT>
  ): CollectionDescription<CollectionMetadataT>;
  
  /** List available schematic names in collection */
  listSchematicNames(
    collection: CollectionDescription<CollectionMetadataT>,
    includeHidden?: boolean
  ): string[];
  
  /** Create schematic description with metadata */
  createSchematicDescription(
    name: string,
    collection: CollectionDescription<CollectionMetadataT>
  ): SchematicDescription<CollectionMetadataT, SchematicMetadataT> | null;
  
  /** Get rule factory for schematic */
  getSchematicRuleFactory<OptionT>(
    schematic: SchematicDescription<CollectionMetadataT, SchematicMetadataT>,
    collection: CollectionDescription<CollectionMetadataT>
  ): RuleFactory<OptionT>;
  
  /** Create source from URL if supported */
  createSourceFromUrl(url: Url, context: SchematicContext): Source | null;
  
  /** Transform options if needed */
  transformOptions<OptionT, ResultT>(
    schematic: SchematicDescription<CollectionMetadataT, SchematicMetadataT>,
    options: OptionT,
    context?: SchematicContext
  ): Observable<ResultT>;
  
  /** Transform execution context */
  transformContext(context: SchematicContext): SchematicContext;
  
  /** Create task executor by name */
  createTaskExecutor(name: string): Observable<TaskExecutor>;
  
  /** Check if task executor exists */
  hasTaskExecutor(name: string): boolean;
  
  /** Default merge strategy for the host */
  readonly defaultMergeStrategy?: MergeStrategy;
}

Collection Interface

Interface representing a collection of schematics with metadata.

/**
 * Represents a collection of schematics with metadata
 */
interface Collection<CollectionMetadataT, SchematicMetadataT> {
  readonly description: CollectionDescription<CollectionMetadataT>;
  readonly baseDescriptions?: Array<CollectionDescription<CollectionMetadataT>>;
  
  /** Create schematic from this collection */
  createSchematic(
    name: string,
    allowPrivate?: boolean
  ): Schematic<CollectionMetadataT, SchematicMetadataT>;
  
  /** List all schematic names in this collection */
  listSchematicNames(includeHidden?: boolean): string[];
}

/**
 * Metadata description for a collection
 */
interface CollectionDescription<T> {
  readonly name: string;
  readonly path: string;
  readonly description?: string;
  readonly extends?: string[];
  readonly dependencies?: string[];
}

Schematic Interface

Interface representing an individual schematic that can be executed.

/**
 * Represents an individual schematic that can be executed
 */
interface Schematic<CollectionMetadataT, SchematicMetadataT> {
  readonly description: SchematicDescription<CollectionMetadataT, SchematicMetadataT>;
  readonly collection: Collection<CollectionMetadataT, SchematicMetadataT>;
  
  /** Execute the schematic with options */
  call<OptionT>(
    options: OptionT,
    host: Observable<Tree>,
    parentContext?: Readonly<SchematicContext>,
    executionOptions?: Partial<ExecutionOptions>
  ): Observable<Tree>;
}

/**
 * Metadata description for a schematic
 */
interface SchematicDescription<CollectionT, SchematicT> {
  readonly name: string;
  readonly collection: CollectionDescription<CollectionT>;
  readonly description?: string;
  readonly schemaJson?: JsonObject;
  readonly hidden?: boolean;
  readonly private?: boolean;
  readonly aliases?: string[];
}

Schematic Context

Execution context providing access to engine, logging, and task management.

/**
 * Execution context for schematics providing engine access and utilities
 */
interface SchematicContext {
  readonly debug: boolean;
  readonly engine: Engine<any, any>;
  readonly logger: logging.LoggerApi;
  readonly schematic: Schematic<any, any>;
  readonly strategy: MergeStrategy;
  readonly interactive: boolean;
  
  /** Add a task to be executed after schematic completion */
  addTask<T>(
    task: TaskConfigurationGenerator<T>,
    dependencies?: Array<TaskId>
  ): TaskId;
}

Usage Examples:

import { SchematicContext, Rule, Tree } from "@angular-devkit/schematics";

function exampleSchematic(options: any): Rule {
  return (tree: Tree, context: SchematicContext) => {
    // Access logger
    context.logger.info(`Generating ${options.name}`);
    
    // Add post-execution task
    context.addTask({
      name: 'npm-install',
      options: {}
    });
    
    // Check if in debug mode
    if (context.debug) {
      context.logger.debug('Debug information');
    }
    
    // Access strategy
    const strategy = context.strategy;
    
    return tree;
  };
}

Engine Implementation

Concrete implementation of the Engine interface.

/**
 * Main engine implementation for executing schematics
 */
class SchematicEngine<CollectionT, SchematicT> implements Engine<CollectionT, SchematicT> {
  constructor(host: EngineHost<CollectionT, SchematicT>, workflow?: Workflow);
  
  readonly defaultMergeStrategy: MergeStrategy;
  readonly workflow: Workflow | null;
  
  createCollection(
    name: string,
    requester?: Collection<CollectionT, SchematicT>
  ): Collection<CollectionT, SchematicT>;
  
  createContext(
    schematic: Schematic<CollectionT, SchematicT>,
    parent?: Readonly<SchematicContext>,
    executionOptions?: Partial<ExecutionOptions>
  ): SchematicContext;
  
  createSchematic(
    name: string,
    collection: Collection<CollectionT, SchematicT>
  ): Schematic<CollectionT, SchematicT>;
  
  createSourceFromUrl(url: Url, context: SchematicContext): Source;
  
  transformOptions<OptionT, ResultT>(
    schematic: Schematic<CollectionT, SchematicT>,
    options: OptionT,
    context?: SchematicContext
  ): Observable<ResultT>;
  
  executePostTasks(): Observable<void>;
}

Collection and Schematic Implementations

Concrete implementations of collections and schematics.

/**
 * Implementation of Collection interface
 */
class CollectionImpl<CollectionT, SchematicT> implements Collection<CollectionT, SchematicT> {
  readonly description: CollectionDescription<CollectionT>;
  readonly baseDescriptions?: Array<CollectionDescription<CollectionT>>;
  
  constructor(
    description: CollectionDescription<CollectionT>,
    engine: SchematicEngine<CollectionT, SchematicT>,
    baseDescriptions?: Array<CollectionDescription<CollectionT>>
  );
  
  createSchematic(name: string, allowPrivate?: boolean): Schematic<CollectionT, SchematicT>;
  listSchematicNames(includeHidden?: boolean): string[];
}

/**
 * Implementation of Schematic interface  
 */
class SchematicImpl<CollectionT, SchematicT> implements Schematic<CollectionT, SchematicT> {
  readonly description: SchematicDescription<CollectionT, SchematicT>;
  readonly collection: Collection<CollectionT, SchematicT>;
  
  constructor(
    description: SchematicDescription<CollectionT, SchematicT>,
    collection: Collection<CollectionT, SchematicT>,
    engine: SchematicEngine<CollectionT, SchematicT>
  );
  
  call<OptionT>(
    options: OptionT,
    host: Observable<Tree>,
    parentContext?: Readonly<SchematicContext>,
    executionOptions?: Partial<ExecutionOptions>
  ): Observable<Tree>;
}

Task System

Task management system for post-schematic execution.

/**
 * Task configuration for post-execution tasks
 */
interface TaskConfigurationGenerator<T = {}> {
  name: string;
  options: T;
}

/**
 * Task executor interface for running tasks
 */
interface TaskExecutor {
  execute(options: TaskConfiguration, context?: TaskContext): Promise<void>;
}

/**
 * Task execution context
 */
interface TaskContext {
  readonly logger: logging.LoggerApi;
  readonly workspaceRoot: string;
  readonly packageManager: string;
}

type TaskId = symbol;

Usage Examples:

import { SchematicContext, TaskConfigurationGenerator } from "@angular-devkit/schematics";

function addNpmInstallTask(context: SchematicContext): void {
  const installTask: TaskConfigurationGenerator = {
    name: 'node-package',
    options: {
      command: 'install',
      packageManager: 'npm'
    }
  };
  
  context.addTask(installTask);
}

function addDependentTasks(context: SchematicContext): void {
  // Add install task first
  const installTaskId = context.addTask({
    name: 'node-package',
    options: { command: 'install' }
  });
  
  // Add build task that depends on install
  context.addTask({
    name: 'run-schematic',
    options: { command: 'build' }
  }, [installTaskId]);
}

Exception Classes

Engine-specific exception types.

/**
 * Unknown URL source protocol error
 */
class UnknownUrlSourceProtocol extends SchematicsException {
  constructor(url: string);
}

/**
 * Unknown collection error
 */
class UnknownCollectionException extends SchematicsException {
  constructor(name: string);
}

/**
 * Circular collection dependency error
 */
class CircularCollectionException extends SchematicsException {
  constructor(name: string);
}

/**
 * Unknown schematic in collection error
 */
class UnknownSchematicException extends SchematicsException {
  constructor(name: string, collection: CollectionDescription<any>);
}

/**
 * Attempt to access private schematic error
 */
class PrivateSchematicException extends SchematicsException {
  constructor(name: string, collection: CollectionDescription<any>);
}

/**
 * Engine conflicting operation error
 */
class SchematicEngineConflictingException extends SchematicsException {}

/**
 * Unregistered task executor error
 */
class UnregisteredTaskException extends SchematicsException {
  constructor(name: string);
}

/**
 * Unknown task dependency error
 */
class UnknownTaskDependencyException extends SchematicsException {
  constructor(id: TaskId);
}

Advanced Usage

Creating a Custom Engine Host:

import { 
  EngineHost, 
  CollectionDescription,
  SchematicDescription,
  RuleFactory 
} from "@angular-devkit/schematics";

class CustomEngineHost implements EngineHost<{}, {}> {
  createCollectionDescription(name: string): CollectionDescription<{}> {
    return {
      name,
      path: `/collections/${name}`,
      description: `Collection ${name}`
    };
  }
  
  listSchematicNames(collection: CollectionDescription<{}>): string[] {
    // Custom logic to discover schematics
    return ['component', 'service', 'module'];
  }
  
  createSchematicDescription(
    name: string, 
    collection: CollectionDescription<{}>
  ): SchematicDescription<{}, {}> | null {
    return {
      name,
      collection,
      description: `Schematic ${name}`
    };
  }
  
  getSchematicRuleFactory<T>(
    schematic: SchematicDescription<{}, {}>,
    collection: CollectionDescription<{}>
  ): RuleFactory<T> {
    // Return appropriate rule factory
    return (options: T) => (tree, context) => {
      // Custom schematic logic
      return tree;
    };
  }
  
  // Implement other required methods...
}

Workflow System

Workflow orchestration for managing schematic execution lifecycle and reporting.

/**
 * Interface for workflow execution with lifecycle management
 */
interface Workflow {
  readonly context: Readonly<WorkflowExecutionContext>;
  
  execute(
    options: Partial<WorkflowExecutionContext> & RequiredWorkflowExecutionContext
  ): Observable<void>;
}

/**
 * Execution context for workflow operations
 */
interface WorkflowExecutionContext {
  collection: string;
  schematic: string;
  options: object;
  debug: boolean;
  logger: logging.Logger;
  parentContext?: Readonly<WorkflowExecutionContext>;
  allowPrivate?: boolean;
}

/**
 * Required workflow execution context properties
 */
interface RequiredWorkflowExecutionContext {
  collection: string;
  schematic: string;
  options: object;
}

/**
 * Lifecycle events emitted during workflow execution
 */
interface LifeCycleEvent {
  kind: 'start' | 'end' | 'workflow-start' | 'workflow-end' | 'post-tasks-start' | 'post-tasks-end';
}

/**
 * Abstract base class for workflow implementations
 */
abstract class BaseWorkflow implements Workflow {
  protected readonly _engine: Engine<{}, {}>;
  protected readonly _engineHost: EngineHost<{}, {}>;
  protected readonly _registry: schema.CoreSchemaRegistry;
  protected readonly _host: virtualFs.Host;
  
  readonly context: Readonly<WorkflowExecutionContext>;
  readonly engine: Engine<{}, {}>;
  readonly engineHost: EngineHost<{}, {}>;
  readonly registry: schema.SchemaRegistry;
  readonly reporter: Observable<DryRunEvent>;
  readonly lifeCycle: Observable<LifeCycleEvent>;
  
  constructor(options: BaseWorkflowOptions);
  
  abstract execute(
    options: Partial<WorkflowExecutionContext> & RequiredWorkflowExecutionContext
  ): Observable<void>;
}

interface BaseWorkflowOptions {
  host: virtualFs.Host;
  engineHost: EngineHost<{}, {}>;
  registry?: schema.CoreSchemaRegistry;
  force?: boolean;
  dryRun?: boolean;
}

Type Definitions

interface ExecutionOptions {
  interactive: boolean;
  dryRun: boolean;
  force: boolean;
  defaults: boolean;
}

interface TaskConfiguration {
  name: string;
  options: any;
  dependencies?: TaskId[];
}

type JsonValue = boolean | number | string | null | JsonArray | JsonObject;
type JsonArray = JsonValue[];
type JsonObject = { [key: string]: JsonValue };

type Url = string;