or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.mdjson-schema.mdlogging.mdnode-integration.mdutilities.mdvirtual-filesystem.mdworkspace.md
tile.json

workspace.mddocs/

Workspace Management

Angular workspace definition system for reading, writing, and manipulating Angular CLI workspace configurations with support for projects, targets, and extensions.

Capabilities

Core Workspace Interfaces

Fundamental interfaces for defining Angular workspace structure.

/**
 * Root workspace definition containing projects and extensions
 * Represents the complete workspace configuration
 */
interface WorkspaceDefinition {
  /** Extension properties for workspace-level configuration */
  readonly extensions: Record<string, JsonValue | undefined>;
  /** Collection of projects in this workspace */
  readonly projects: ProjectDefinitionCollection;
}

/**
 * Individual project definition within a workspace
 * Contains project-specific configuration, targets, and metadata
 */
interface ProjectDefinition {
  /** Extension properties for project-level configuration */
  readonly extensions: Record<string, JsonValue | undefined>;
  /** Collection of build targets for this project */
  readonly targets: TargetDefinitionCollection;
  /** Root directory path for the project relative to workspace */
  root: string;
  /** Optional prefix for generated selectors and file names */
  prefix?: string;
  /** Optional source root directory relative to project root */
  sourceRoot?: string;
}

/**
 * Build target definition specifying how to build, test, or serve a project
 * Contains builder reference, options, and configuration variants
 */
interface TargetDefinition {
  /** Reference to the builder package and function */
  builder: string;
  /** Default options for this target */
  options?: Record<string, JsonValue | undefined>;
  /** Named configuration variants with option overrides */
  configurations?: Record<string, Record<string, JsonValue | undefined> | undefined>;
}

/**
 * Listener function type for collection change events
 * Called when items are added, removed, or modified in collections
 */
type DefinitionCollectionListener<T> = (
  name: string,
  newValue: T | undefined,
  collection: DefinitionCollection<T>
) => void;

Collection Classes

Map-like collections for managing projects and targets with change tracking.

/**
 * Base interface for definition collections
 * Provides Map-like interface with additional workspace-specific functionality
 */
interface DefinitionCollection<T> extends ReadonlyMap<string, T> {
  /**
   * Add a new item to the collection
   * @param name - Item name/key
   * @param definition - Item definition
   * @returns The added item
   */
  add(name: string, definition: T): T;
  
  /**
   * Set or update an item in the collection
   * @param name - Item name/key
   * @param definition - Item definition
   * @returns The collection instance for chaining
   */
  set(name: string, definition: T): this;
  
  /**
   * Remove an item from the collection
   * @param name - Item name/key to remove
   * @returns True if item was removed, false if not found
   */
  delete(name: string): boolean;
  
  /**
   * Add a listener for collection changes
   * @param listener - Function to call on changes
   */
  addListener(listener: DefinitionCollectionListener<T>): void;
  
  /**
   * Remove a change listener
   * @param listener - Listener function to remove
   */
  removeListener(listener: DefinitionCollectionListener<T>): void;
}

/**
 * Map-like collection for managing projects within a workspace
 * Provides change tracking and validation for project definitions
 */
class ProjectDefinitionCollection implements DefinitionCollection<ProjectDefinition> {
  /** Number of projects in the collection */
  readonly size: number;
  
  /**
   * Get a project by name
   * @param name - Project name
   * @returns Project definition or undefined if not found
   */
  get(name: string): ProjectDefinition | undefined;
  
  /**
   * Check if a project exists
   * @param name - Project name
   * @returns True if project exists
   */
  has(name: string): boolean;
  
  /**
   * Add a new project to the workspace
   * @param name - Project name (must be unique)
   * @param definition - Project definition
   * @returns The added project definition
   */
  add(name: string, definition: ProjectDefinition): ProjectDefinition;
  
  /**
   * Set or update a project
   * @param name - Project name
   * @param definition - Project definition
   * @returns The collection instance for chaining
   */
  set(name: string, definition: ProjectDefinition): this;
  
  /**
   * Remove a project from the workspace
   * @param name - Project name to remove
   * @returns True if project was removed
   */
  delete(name: string): boolean;
  
  /**
   * Iterate over project names
   */
  keys(): IterableIterator<string>;
  
  /**
   * Iterate over project definitions
   */
  values(): IterableIterator<ProjectDefinition>;
  
  /**
   * Iterate over [name, definition] pairs
   */
  entries(): IterableIterator<[string, ProjectDefinition]>;
  
  /**
   * Iterate over [name, definition] pairs
   */
  [Symbol.iterator](): IterableIterator<[string, ProjectDefinition]>;
  
  addListener(listener: DefinitionCollectionListener<ProjectDefinition>): void;
  removeListener(listener: DefinitionCollectionListener<ProjectDefinition>): void;
}

/**
 * Map-like collection for managing build targets within a project
 * Provides change tracking and validation for target definitions
 */
class TargetDefinitionCollection implements DefinitionCollection<TargetDefinition> {
  /** Number of targets in the collection */
  readonly size: number;
  
  /**
   * Get a target by name
   * @param name - Target name
   * @returns Target definition or undefined if not found
   */
  get(name: string): TargetDefinition | undefined;
  
  /**
   * Check if a target exists
   * @param name - Target name
   * @returns True if target exists
   */
  has(name: string): boolean;
  
  /**
   * Add a new target to the project
   * @param name - Target name (must be unique within project)
   * @param definition - Target definition
   * @returns The added target definition
   */
  add(name: string, definition: TargetDefinition): TargetDefinition;
  
  /**
   * Set or update a target
   * @param name - Target name
   * @param definition - Target definition
   * @returns The collection instance for chaining
   */
  set(name: string, definition: TargetDefinition): this;
  
  /**
   * Remove a target from the project
   * @param name - Target name to remove
   * @returns True if target was removed
   */
  delete(name: string): boolean;
  
  /**
   * Iterate over target names
   */
  keys(): IterableIterator<string>;
  
  /**
   * Iterate over target definitions
   */
  values(): IterableIterator<TargetDefinition>;
  
  /**
   * Iterate over [name, definition] pairs
   */
  entries(): IterableIterator<[string, TargetDefinition]>;
  
  /**
   * Iterate over [name, definition] pairs
   */
  [Symbol.iterator](): IterableIterator<[string, TargetDefinition]>;
  
  addListener(listener: DefinitionCollectionListener<TargetDefinition>): void;
  removeListener(listener: DefinitionCollectionListener<TargetDefinition>): void;
}

Workspace Operations

Core functions for reading and writing workspace configurations.

/**
 * Host interface for workspace file operations
 * Abstracts file system operations for workspace management
 */
interface WorkspaceHost {
  /**
   * Read file content as string
   * @param path - File path to read
   * @returns Promise resolving to file content
   */
  readFile(path: string): Promise<string>;
  
  /**
   * Write file content
   * @param path - File path to write
   * @param data - Content to write
   * @returns Promise completing when write is done
   */
  writeFile(path: string, data: string): Promise<void>;
  
  /**
   * Check if path is a directory
   * @param path - Path to check
   * @returns Promise resolving to true if path is directory
   */
  isDirectory(path: string): Promise<boolean>;
  
  /**
   * Check if path is a file
   * @param path - Path to check
   * @returns Promise resolving to true if path is file
   */
  isFile(path: string): Promise<boolean>;
}

/**
 * Create a workspace host from a virtual file system host
 * Adapts virtual FS host interface to workspace host interface
 * @param host - Virtual file system host
 * @returns Workspace host implementation
 */
function createWorkspaceHost(host: virtualFs.Host): WorkspaceHost;

/**
 * Supported workspace file formats
 */
enum WorkspaceFormat {
  /** JSON format used by Angular CLI */
  JSON = 0
}

/**
 * Read workspace definition from host
 * Parses workspace configuration and creates definition objects
 * @param path - Path to workspace directory or configuration file
 * @param host - Host for file operations
 * @param format - Optional format specification (defaults to JSON)
 * @returns Promise resolving to workspace definition and metadata
 */
function readWorkspace(
  path: string,
  host: WorkspaceHost,
  format?: WorkspaceFormat
): Promise<{ workspace: WorkspaceDefinition }>;

/**
 * Write workspace definition to host
 * Serializes workspace definition and writes to storage
 * @param workspace - Workspace definition to write
 * @param host - Host for file operations
 * @param path - Optional path override (uses original path if not specified)
 * @param format - Optional format specification (defaults to JSON)
 * @returns Promise completing when write is done
 */
function writeWorkspace(
  workspace: WorkspaceDefinition,
  host: WorkspaceHost,
  path?: string,
  format?: WorkspaceFormat
): Promise<void>;

Workspace Metadata and Utilities

Additional utilities for workspace management and metadata handling.

/**
 * Workspace metadata containing format and location information
 */
interface WorkspaceMetadata {
  /** Format of the workspace file */
  format: WorkspaceFormat;
  /** Path to the workspace file */
  filePath: string;
  /** Whether the workspace uses the new format */
  isNewFormat: boolean;
}

/**
 * Options for workspace reading operations
 */
interface ReadWorkspaceOptions {
  /** Whether to allow legacy format */
  allowLegacy?: boolean;
  /** Custom JSON schema for validation */
  schema?: JsonObject;
}

/**
 * Options for workspace writing operations
 */
interface WriteWorkspaceOptions {
  /** Whether to format the output JSON */
  pretty?: boolean;
  /** Custom indentation for JSON formatting */
  indent?: string | number;
}

/**
 * Validate workspace definition against schema
 * @param workspace - Workspace definition to validate
 * @param schema - Optional schema for validation
 * @returns Validation result with errors if any
 */
function validateWorkspace(
  workspace: WorkspaceDefinition,
  schema?: JsonObject
): { valid: boolean; errors: string[] };

/**
 * Create a new empty workspace definition
 * @returns New workspace definition with empty projects collection
 */
function createWorkspaceDefinition(): WorkspaceDefinition;

/**
 * Create a new empty project definition
 * @param root - Project root directory
 * @param options - Optional project configuration
 * @returns New project definition
 */
function createProjectDefinition(
  root: string,
  options?: {
    prefix?: string;
    sourceRoot?: string;
    extensions?: Record<string, JsonValue>;
  }
): ProjectDefinition;

/**
 * Create a new target definition
 * @param builder - Builder package and function reference
 * @param options - Optional target configuration
 * @returns New target definition
 */
function createTargetDefinition(
  builder: string,
  options?: {
    options?: Record<string, JsonValue>;
    configurations?: Record<string, Record<string, JsonValue>>;
  }
): TargetDefinition;

Usage Examples

Reading and Writing Workspaces

import { workspaces, virtualFs } from "@angular-devkit/core";
import { NodeJsSyncHost } from "@angular-devkit/core/node";

// Create workspace host
const fsHost = new NodeJsSyncHost();
const host = workspaces.createWorkspaceHost(fsHost);

// Read workspace
const { workspace } = await workspaces.readWorkspace('/path/to/workspace/', host);

console.log(`Workspace has ${workspace.projects.size} projects`);

// List all projects
for (const [name, project] of workspace.projects) {
  console.log(`Project: ${name} at ${project.root}`);
  console.log(`  Targets: ${Array.from(project.targets.keys()).join(', ')}`);
}

// Modify workspace
const newProject = workspaces.createProjectDefinition('projects/new-app', {
  prefix: 'app',
  sourceRoot: 'projects/new-app/src'
});

workspace.projects.add('new-app', newProject);

// Write workspace back
await workspaces.writeWorkspace(workspace, host);

Working with Projects and Targets

import { workspaces } from "@angular-devkit/core";

// Get specific project
const project = workspace.projects.get('my-app');
if (!project) {
  throw new Error('Project not found');
}

// Add a new target
const buildTarget = workspaces.createTargetDefinition(
  '@angular-devkit/build-angular:browser',
  {
    options: {
      outputPath: 'dist/my-app',
      index: 'src/index.html',
      main: 'src/main.ts',
      polyfills: 'src/polyfills.ts',
      tsConfig: 'tsconfig.app.json'
    },
    configurations: {
      production: {
        budgets: [{
          type: 'initial',
          maximumWarning: '2mb',
          maximumError: '5mb'
        }],
        outputHashing: 'all'
      },
      development: {
        buildOptimizer: false,
        optimization: false,
        vendorChunk: true,
        extractLicenses: false,
        sourceMap: true,
        namedChunks: true
      }
    }
  }
);

project.targets.add('build', buildTarget);

// Modify existing target
const testTarget = project.targets.get('test');
if (testTarget && testTarget.options) {
  testTarget.options.codeCoverage = true;
  testTarget.options.browsers = 'ChromeHeadless';
}

Workspace Extensions and Metadata

import { workspaces } from "@angular-devkit/core";

// Add workspace-level extensions
workspace.extensions['version'] = '1.0.0';
workspace.extensions['cli'] = {
  defaultCollection: '@angular/schematics',
  analytics: false
};

// Add project-level extensions
const project = workspace.projects.get('my-app')!;
project.extensions['architect'] = {
  defaultProject: 'my-app'
};

// Access target configurations
const buildTarget = project.targets.get('build')!;
console.log('Available configurations:', Object.keys(buildTarget.configurations || {}));

// Get specific configuration
const prodConfig = buildTarget.configurations?.['production'];
if (prodConfig) {
  console.log('Production output hashing:', prodConfig.outputHashing);
}

Change Tracking and Listeners

import { workspaces } from "@angular-devkit/core";

// Add listeners for project changes
workspace.projects.addListener((name, newValue, collection) => {
  if (newValue) {
    console.log(`Project ${name} was added or updated`);
  } else {
    console.log(`Project ${name} was removed`);
  }
});

// Add listeners for target changes in a specific project
const project = workspace.projects.get('my-app')!;
project.targets.addListener((name, newValue, collection) => {
  if (newValue) {
    console.log(`Target ${name} was added or updated in my-app`);
    console.log(`Builder: ${newValue.builder}`);
  } else {
    console.log(`Target ${name} was removed from my-app`);
  }
});

// Make changes (listeners will be called)
project.targets.add('deploy', {
  builder: '@angular/fire:deploy',
  options: {
    prerender: true
  }
});

Workspace Validation

import { workspaces } from "@angular-devkit/core";

// Validate workspace
const validationResult = workspaces.validateWorkspace(workspace);

if (!validationResult.valid) {
  console.error('Workspace validation failed:');
  validationResult.errors.forEach(error => {
    console.error(`  - ${error}`);
  });
} else {
  console.log('Workspace is valid');
}

// Create workspace from scratch
const newWorkspace = workspaces.createWorkspaceDefinition();

// Add workspace-level configuration
newWorkspace.extensions['version'] = 1;
newWorkspace.extensions['newProjectRoot'] = 'projects';

// Add a library project
const libProject = workspaces.createProjectDefinition('projects/my-lib', {
  prefix: 'lib',
  sourceRoot: 'projects/my-lib/src'
});

// Add build target for library
const libBuildTarget = workspaces.createTargetDefinition(
  '@angular-devkit/build-angular:ng-packagr',
  {
    options: {
      project: 'projects/my-lib/ng-package.json'
    }
  }
);

libProject.targets.add('build', libBuildTarget);
newWorkspace.projects.add('my-lib', libProject);

// Write new workspace
await workspaces.writeWorkspace(newWorkspace, host, '/path/to/new-workspace/');