or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

angular-cli-adapter.mdconfiguration.mdindex.mdlogging.mdpackage-manager.mdproject-graph.mdtree-api.mdworkspace-management.mdworkspace-root.md

angular-cli-adapter.mddocs/

0

# Angular CLI Adapter

1

2

Bridge functionality for running Angular schematics, migrations, and builders within Nx workspaces. Provides compatibility layer for Angular DevKit tools and enables seamless integration with Angular CLI workflows.

3

4

## Capabilities

5

6

### Target Execution

7

8

Schedule and execute Angular CLI targets (builders) within Nx workspaces.

9

10

```typescript { .api }

11

/**

12

* Schedules Angular CLI target execution

13

* @param root - Workspace root directory

14

* @param opts - Target execution options

15

* @param verbose - Enable verbose logging

16

* @returns Promise resolving to Observable of build results

17

*/

18

export function scheduleTarget(

19

root: string,

20

opts: {

21

/** Project name to execute target for */

22

project: string;

23

/** Target name to execute */

24

target: string;

25

/** Configuration name (e.g., 'production', 'development') */

26

configuration: string;

27

/** Additional options to pass to the target */

28

runOptions: any;

29

},

30

verbose: boolean

31

): Promise<Observable<BuilderOutput>>;

32

33

/** Build output interface from Angular DevKit */

34

export interface BuilderOutput {

35

success: boolean;

36

error?: string;

37

target?: Target;

38

outputPath?: string;

39

}

40

41

/** Target reference interface */

42

export interface Target {

43

project: string;

44

target: string;

45

configuration?: string;

46

}

47

48

/** Observable interface for reactive programming */

49

export interface Observable<T> {

50

subscribe(observer: {

51

next?: (value: T) => void;

52

error?: (error: any) => void;

53

complete?: () => void;

54

}): { unsubscribe(): void };

55

}

56

```

57

58

### Schematic Generation

59

60

Run Angular schematics for code generation and project setup.

61

62

```typescript { .api }

63

/**

64

* Runs Angular schematic generation

65

* @param root - Workspace root directory

66

* @param opts - Generation options

67

* @param verbose - Enable verbose logging

68

* @returns Promise resolving to exit code (0 for success)

69

*/

70

export function generate(root: string, opts: GenerateOptions, verbose: boolean): Promise<number>;

71

72

/** Options for schematic generation */

73

export interface GenerateOptions {

74

/** Collection name (e.g., '@angular/core', '@nx/angular') */

75

collection: string;

76

/** Schematic name to run */

77

name: string;

78

/** Options to pass to the schematic */

79

options: Record<string, any>;

80

/** Whether to perform a dry run */

81

dryRun?: boolean;

82

/** Whether to force overwrite existing files */

83

force?: boolean;

84

}

85

```

86

87

### Migration Execution

88

89

Execute package migrations for workspace updates and transformations.

90

91

```typescript { .api }

92

/**

93

* Executes migrations for package updates

94

* @param root - Workspace root directory

95

* @param packageName - Name of the package to migrate

96

* @param migrationName - Name of the specific migration to run

97

* @param isVerbose - Enable verbose logging

98

* @returns Promise with migration results

99

*/

100

export function runMigration(

101

root: string,

102

packageName: string,

103

migrationName: string,

104

isVerbose: boolean

105

): Promise<{

106

/** Log messages from the migration */

107

loggingQueue: string[];

108

/** Whether the migration made any changes */

109

madeChanges: boolean;

110

}>;

111

```

112

113

### Schematic Wrapping

114

115

Utilities for wrapping Angular DevKit schematics for use within Nx.

116

117

```typescript { .api }

118

/**

119

* Wraps Angular DevKit schematic for Nx usage

120

* @param collectionName - Name of the schematic collection

121

* @param generatorName - Name of the generator/schematic

122

* @returns Wrapped schematic function compatible with Nx Tree API

123

*/

124

export function wrapAngularDevkitSchematic(

125

collectionName: string,

126

generatorName: string

127

): (host: Tree, generatorOptions: { [k: string]: any }) => Promise<void>;

128

```

129

130

### Virtual File System Integration

131

132

Classes for integrating Angular DevKit with Nx file system operations.

133

134

```typescript { .api }

135

/**

136

* Virtual filesystem host for Angular DevKit integration

137

*/

138

export class NxScopedHost {

139

constructor(root: string);

140

141

/** Read file as string */

142

readFile(path: string): Promise<string>;

143

/** Write file content */

144

writeFile(path: string, content: string): Promise<void>;

145

/** Check if file exists */

146

exists(path: string): Promise<boolean>;

147

/** Delete file */

148

delete(path: string): Promise<void>;

149

/** Rename file */

150

rename(from: string, to: string): Promise<void>;

151

/** List directory contents */

152

list(path: string): Promise<string[]>;

153

}

154

155

/**

156

* Specialized host for wrapped schematics

157

*/

158

export class NxScopeHostUsedForWrappedSchematics extends NxScopedHost {

159

constructor(root: string, host: Tree);

160

}

161

```

162

163

### Logging and Utilities

164

165

Utilities for logging and converting data formats.

166

167

```typescript { .api }

168

/**

169

* Creates Angular DevKit logger

170

* @param isVerbose - Enable verbose logging

171

* @returns Logger instance compatible with Angular DevKit

172

*/

173

export function getLogger(isVerbose?: boolean): logging.Logger;

174

175

/**

176

* Converts ArrayBuffer to string

177

* @param buffer - ArrayBuffer to convert

178

* @returns String representation of the buffer

179

*/

180

export function arrayBufferToString(buffer: any): string;

181

```

182

183

### Testing Utilities

184

185

Functions for testing and mocking schematic operations.

186

187

```typescript { .api }

188

/**

189

* Override collection resolution for testing

190

* @param collections - Map of collection names to paths

191

*/

192

export function overrideCollectionResolutionForTesting(collections: { [name: string]: string }): void;

193

194

/**

195

* Mock schematics for testing

196

* @param schematics - Map of schematic names to mock implementations

197

*/

198

export function mockSchematicsForTesting(schematics: {

199

[name: string]: (host: Tree, generatorOptions: { [k: string]: any }) => Promise<void>

200

}): void;

201

```

202

203

## Usage Examples

204

205

### Running Angular CLI Targets

206

207

```typescript

208

import { scheduleTarget } from "@nrwl/tao/commands/ngcli-adapter";

209

import { workspaceRoot } from "@nrwl/tao/utils/app-root";

210

211

async function buildProject(projectName: string, configuration: string = 'production') {

212

try {

213

const buildResult$ = await scheduleTarget(

214

workspaceRoot,

215

{

216

project: projectName,

217

target: 'build',

218

configuration: configuration,

219

runOptions: {

220

optimization: true,

221

sourceMap: false

222

}

223

},

224

true // verbose logging

225

);

226

227

// Subscribe to build results

228

buildResult$.subscribe({

229

next: (result) => {

230

if (result.success) {

231

console.log(`Build completed successfully`);

232

if (result.outputPath) {

233

console.log(`Output: ${result.outputPath}`);

234

}

235

} else {

236

console.error(`Build failed: ${result.error}`);

237

}

238

},

239

error: (error) => {

240

console.error('Build error:', error);

241

},

242

complete: () => {

243

console.log('Build process completed');

244

}

245

});

246

247

} catch (error) {

248

console.error('Failed to schedule build target:', error);

249

}

250

}

251

252

// Usage

253

buildProject('my-app', 'production');

254

```

255

256

### Running Schematics

257

258

```typescript

259

import { generate, type GenerateOptions } from "@nrwl/tao/commands/ngcli-adapter";

260

import { workspaceRoot } from "@nrwl/tao/utils/app-root";

261

import { logger } from "@nrwl/tao/shared/logger";

262

263

async function generateComponent(name: string, project: string) {

264

const options: GenerateOptions = {

265

collection: '@angular/core',

266

name: 'component',

267

options: {

268

name: name,

269

project: project,

270

style: 'scss',

271

skipTests: false,

272

changeDetection: 'OnPush'

273

},

274

dryRun: false,

275

force: false

276

};

277

278

try {

279

const exitCode = await generate(workspaceRoot, options, true);

280

281

if (exitCode === 0) {

282

logger.info(`Component '${name}' generated successfully`);

283

} else {

284

logger.error(`Component generation failed with exit code: ${exitCode}`);

285

}

286

287

return exitCode;

288

} catch (error) {

289

logger.error('Failed to generate component:', error);

290

return 1;

291

}

292

}

293

294

// Generate library

295

async function generateLibrary(name: string) {

296

const options: GenerateOptions = {

297

collection: '@nx/angular',

298

name: 'library',

299

options: {

300

name: name,

301

buildable: true,

302

publishable: false,

303

routing: false,

304

lazy: false

305

}

306

};

307

308

const exitCode = await generate(workspaceRoot, options, true);

309

return exitCode === 0;

310

}

311

312

// Usage

313

generateComponent('user-profile', 'my-app');

314

generateLibrary('shared-utils');

315

```

316

317

### Running Migrations

318

319

```typescript

320

import { runMigration } from "@nrwl/tao/commands/ngcli-adapter";

321

import { workspaceRoot } from "@nrwl/tao/utils/app-root";

322

import { logger } from "@nrwl/tao/shared/logger";

323

324

async function migratePackage(packageName: string, migrationName: string) {

325

try {

326

logger.info(`Running migration: ${packageName}:${migrationName}`);

327

328

const result = await runMigration(

329

workspaceRoot,

330

packageName,

331

migrationName,

332

true // verbose

333

);

334

335

// Log migration output

336

result.loggingQueue.forEach(message => {

337

console.log(message);

338

});

339

340

if (result.madeChanges) {

341

logger.info('Migration completed with changes');

342

} else {

343

logger.info('Migration completed without changes');

344

}

345

346

return result;

347

} catch (error) {

348

logger.error(`Migration failed: ${error.message}`);

349

throw error;

350

}

351

}

352

353

// Example: Migrate Angular to newer version

354

async function migrateAngular() {

355

try {

356

// Run Angular update migration

357

await migratePackage('@angular/core', 'migration-v15');

358

359

// Run additional migrations if needed

360

await migratePackage('@angular/cli', 'update-workspace-config');

361

362

logger.info('Angular migration completed successfully');

363

} catch (error) {

364

logger.error('Angular migration failed:', error);

365

}

366

}

367

368

migrateAngular();

369

```

370

371

### Custom Schematic Wrapping

372

373

```typescript

374

import {

375

wrapAngularDevkitSchematic,

376

NxScopeHostUsedForWrappedSchematics

377

} from "@nrwl/tao/commands/ngcli-adapter";

378

import { FsTree } from "@nrwl/tao/shared/tree";

379

import { workspaceRoot } from "@nrwl/tao/utils/app-root";

380

381

// Wrap an Angular schematic for use with Nx Tree API

382

const wrappedComponentSchematic = wrapAngularDevkitSchematic(

383

'@angular/core',

384

'component'

385

);

386

387

async function generateComponentWithNxTree(name: string, path: string) {

388

const tree = new FsTree(workspaceRoot);

389

390

try {

391

// Use the wrapped schematic with Nx Tree

392

await wrappedComponentSchematic(tree, {

393

name: name,

394

path: path,

395

style: 'scss',

396

skipTests: false

397

});

398

399

// Apply changes to file system

400

const changes = tree.listChanges();

401

console.log(`Generated ${changes.length} files for component '${name}'`);

402

403

// You can review changes before applying

404

changes.forEach(change => {

405

console.log(`${change.type}: ${change.path}`);

406

});

407

408

// Apply changes

409

flushChanges(tree.root, changes);

410

411

} catch (error) {

412

console.error('Failed to generate component:', error);

413

}

414

}

415

416

generateComponentWithNxTree('feature-component', 'src/app/features');

417

```

418

419

### Testing with Mocked Schematics

420

421

```typescript

422

import {

423

mockSchematicsForTesting,

424

overrideCollectionResolutionForTesting

425

} from "@nrwl/tao/commands/ngcli-adapter";

426

import { FsTree } from "@nrwl/tao/shared/tree";

427

428

// Set up testing environment

429

function setupSchematicTesting() {

430

// Override collection paths for testing

431

overrideCollectionResolutionForTesting({

432

'@nx/angular': '/path/to/test/collections/nx-angular',

433

'@angular/core': '/path/to/test/collections/angular-core'

434

});

435

436

// Mock specific schematics

437

mockSchematicsForTesting({

438

'component': async (tree, options) => {

439

// Mock component generation

440

const componentPath = `${options.path}/${options.name}.component.ts`;

441

tree.write(componentPath, `

442

import { Component } from '@angular/core';

443

444

@Component({

445

selector: 'app-${options.name}',

446

template: '<div>Mock ${options.name} component</div>'

447

})

448

export class ${options.name}Component {}

449

`);

450

},

451

452

'service': async (tree, options) => {

453

// Mock service generation

454

const servicePath = `${options.path}/${options.name}.service.ts`;

455

tree.write(servicePath, `

456

import { Injectable } from '@angular/core';

457

458

@Injectable({

459

providedIn: 'root'

460

})

461

export class ${options.name}Service {}

462

`);

463

}

464

});

465

}

466

467

// Use in tests

468

describe('Schematic Integration', () => {

469

beforeEach(() => {

470

setupSchematicTesting();

471

});

472

473

it('should generate component using mocked schematic', async () => {

474

const tree = new FsTree('/test-workspace');

475

476

// This will use the mocked schematic

477

const wrappedSchematic = wrapAngularDevkitSchematic('@angular/core', 'component');

478

await wrappedSchematic(tree, {

479

name: 'test-component',

480

path: 'src/app'

481

});

482

483

expect(tree.exists('src/app/test-component.component.ts')).toBe(true);

484

});

485

});

486

```

487

488

### Logging Integration

489

490

```typescript

491

import { getLogger, arrayBufferToString } from "@nrwl/tao/commands/ngcli-adapter";

492

import { logger as nxLogger } from "@nrwl/tao/shared/logger";

493

494

// Create Angular DevKit logger that integrates with Nx logging

495

const angularLogger = getLogger(true); // verbose logging

496

497

// Use Angular logger for DevKit operations

498

angularLogger.info('Starting Angular DevKit operation');

499

angularLogger.warn('This is a warning from Angular DevKit');

500

501

// Convert binary data for logging

502

const binaryData = new ArrayBuffer(8);

503

const stringData = arrayBufferToString(binaryData);

504

nxLogger.debug('Binary data as string:', stringData);

505

506

// Custom logging bridge

507

function bridgeAngularToNxLogging(angularLogger: any, nxLogger: any) {

508

const originalInfo = angularLogger.info;

509

const originalWarn = angularLogger.warn;

510

const originalError = angularLogger.error;

511

512

angularLogger.info = (message: string) => {

513

nxLogger.info(`[Angular] ${message}`);

514

return originalInfo.call(angularLogger, message);

515

};

516

517

angularLogger.warn = (message: string) => {

518

nxLogger.warn(`[Angular] ${message}`);

519

return originalWarn.call(angularLogger, message);

520

};

521

522

angularLogger.error = (message: string) => {

523

nxLogger.error(`[Angular] ${message}`);

524

return originalError.call(angularLogger, message);

525

};

526

}

527

528

bridgeAngularToNxLogging(angularLogger, nxLogger);

529

```

530

531

## Integration with Workspace Management

532

533

The Angular CLI adapter works seamlessly with other @nrwl/tao APIs:

534

535

```typescript

536

import { scheduleTarget } from "@nrwl/tao/commands/ngcli-adapter";

537

import { Workspaces } from "@nrwl/tao/shared/workspace";

538

import { logger } from "@nrwl/tao/shared/logger";

539

import { workspaceRoot } from "@nrwl/tao/utils/app-root";

540

541

async function buildAllApps() {

542

const workspaces = new Workspaces(workspaceRoot);

543

const projects = workspaces.readProjectsConfigurations();

544

545

// Find all application projects

546

const apps = Object.entries(projects.projects)

547

.filter(([_, config]) => config.projectType === 'application')

548

.map(([name]) => name);

549

550

logger.info(`Found ${apps.length} applications to build`);

551

552

// Build each app

553

for (const appName of apps) {

554

try {

555

logger.info(`Building ${appName}...`);

556

557

const buildResult$ = await scheduleTarget(

558

workspaceRoot,

559

{

560

project: appName,

561

target: 'build',

562

configuration: 'production',

563

runOptions: {}

564

},

565

false // not verbose for batch operation

566

);

567

568

await new Promise((resolve, reject) => {

569

buildResult$.subscribe({

570

next: (result) => {

571

if (result.success) {

572

logger.info(`✓ ${appName} built successfully`);

573

} else {

574

logger.error(`✗ ${appName} build failed: ${result.error}`);

575

}

576

},

577

error: reject,

578

complete: resolve

579

});

580

});

581

582

} catch (error) {

583

logger.error(`Failed to build ${appName}:`, error);

584

}

585

}

586

587

logger.info('Batch build completed');

588

}

589

```