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

tree-api.mddocs/

0

# Tree API

1

2

Virtual file system API for code generation and file system operations with change tracking. Provides a virtual abstraction over the file system that tracks changes and enables batch operations.

3

4

## Capabilities

5

6

### Tree Interface

7

8

Main virtual file system interface for reading, writing, and manipulating files.

9

10

```typescript { .api }

11

/**

12

* Virtual file system interface with change tracking

13

*/

14

export interface Tree {

15

/** Workspace root directory path */

16

root: string;

17

18

/** Read file as Buffer */

19

read(filePath: string): Buffer | null;

20

/** Read file as string with encoding */

21

read(filePath: string, encoding: BufferEncoding): string | null;

22

23

/** Write content to file */

24

write(filePath: string, content: Buffer | string, options?: TreeWriteOptions): void;

25

/** Check if file exists */

26

exists(filePath: string): boolean;

27

/** Delete file */

28

delete(filePath: string): void;

29

/** Rename/move file */

30

rename(from: string, to: string): void;

31

/** Check if path is a file (not directory) */

32

isFile(filePath: string): boolean;

33

/** List child files/directories in a directory */

34

children(dirPath: string): string[];

35

/** Get list of all tracked changes */

36

listChanges(): FileChange[];

37

/** Change file permissions */

38

changePermissions(filePath: string, mode: Mode): void;

39

}

40

41

/** File write options */

42

export interface TreeWriteOptions {

43

/** File permissions mode */

44

mode?: Mode;

45

}

46

47

/** File permission mode type */

48

export type Mode = number;

49

```

50

51

### Change Tracking

52

53

Types for tracking and applying file system changes.

54

55

```typescript { .api }

56

/**

57

* Describes a file system change operation

58

*/

59

export interface FileChange {

60

/** Path of the file being changed */

61

path: string;

62

/** Type of change operation */

63

type: 'CREATE' | 'DELETE' | 'UPDATE';

64

/** File content (null for deletions) */

65

content: Buffer | null;

66

/** Write options for the change */

67

options?: TreeWriteOptions;

68

}

69

```

70

71

### Tree Implementation

72

73

Concrete file system-backed implementation of the Tree interface.

74

75

```typescript { .api }

76

/**

77

* File system-backed implementation of Tree interface

78

*/

79

export class FsTree implements Tree {

80

constructor(root: string, isVerbose?: boolean);

81

82

root: string;

83

read(filePath: string): Buffer | null;

84

read(filePath: string, encoding: BufferEncoding): string | null;

85

write(filePath: string, content: Buffer | string, options?: TreeWriteOptions): void;

86

exists(filePath: string): boolean;

87

delete(filePath: string): void;

88

rename(from: string, to: string): void;

89

isFile(filePath: string): boolean;

90

children(dirPath: string): string[];

91

listChanges(): FileChange[];

92

changePermissions(filePath: string, mode: Mode): void;

93

}

94

```

95

96

### Change Application

97

98

Functions for applying tracked changes to the actual file system.

99

100

```typescript { .api }

101

/**

102

* Applies tracked changes to the file system

103

* @param root - Root directory to apply changes to

104

* @param fileChanges - Array of changes to apply

105

*/

106

export function flushChanges(root: string, fileChanges: FileChange[]): void;

107

108

/**

109

* Prints a summary of tracked changes

110

* @param fileChanges - Array of changes to print

111

* @param indent - Indentation string for formatting (defaults to empty string)

112

*/

113

export function printChanges(fileChanges: FileChange[], indent?: string): void;

114

```

115

116

## Usage Examples

117

118

### Basic File Operations

119

120

```typescript

121

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

122

123

// Create a tree for the current workspace

124

const tree = new FsTree(process.cwd());

125

126

// Read files

127

const packageJson = tree.read('package.json', 'utf-8');

128

const binaryFile = tree.read('logo.png'); // Returns Buffer

129

130

// Check file existence

131

if (tree.exists('src/app.ts')) {

132

console.log('App file exists');

133

}

134

135

// Write files

136

tree.write('src/new-component.ts', `

137

export class NewComponent {

138

constructor() {

139

console.log('New component created');

140

}

141

}

142

`);

143

144

// Create directories by writing files with paths

145

tree.write('src/utils/helper.ts', 'export const helper = () => {};');

146

```

147

148

### Change Tracking and Application

149

150

```typescript

151

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

152

153

const tree = new FsTree('/path/to/workspace');

154

155

// Make several changes

156

tree.write('new-file.ts', 'export const newFunction = () => {};');

157

tree.write('src/existing.ts', 'updated content');

158

tree.delete('old-file.ts');

159

tree.rename('temp.ts', 'renamed.ts');

160

161

// Review changes before applying

162

const changes = tree.listChanges();

163

console.log(`Found ${changes.length} changes:`);

164

printChanges(changes, ' ');

165

166

// Apply all changes to the file system

167

flushChanges(tree.root, changes);

168

console.log('All changes applied to file system');

169

```

170

171

### File System Navigation

172

173

```typescript

174

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

175

176

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

177

178

// List directory contents

179

const srcFiles = tree.children('src');

180

console.log('Source files:', srcFiles);

181

182

// Check file types

183

srcFiles.forEach(file => {

184

const fullPath = `src/${file}`;

185

if (tree.isFile(fullPath)) {

186

console.log(`${file} is a file`);

187

} else {

188

console.log(`${file} is a directory`);

189

}

190

});

191

192

// Recursively list all TypeScript files

193

function listTsFiles(tree: FsTree, dir: string = ''): string[] {

194

const tsFiles: string[] = [];

195

196

try {

197

const children = tree.children(dir);

198

199

for (const child of children) {

200

const childPath = dir ? `${dir}/${child}` : child;

201

202

if (tree.isFile(childPath) && child.endsWith('.ts')) {

203

tsFiles.push(childPath);

204

} else if (!tree.isFile(childPath)) {

205

tsFiles.push(...listTsFiles(tree, childPath));

206

}

207

}

208

} catch (error) {

209

// Directory might not exist or be accessible

210

}

211

212

return tsFiles;

213

}

214

215

const allTsFiles = listTsFiles(tree, 'src');

216

console.log('All TypeScript files:', allTsFiles);

217

```

218

219

### Code Generation Patterns

220

221

```typescript

222

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

223

224

function generateComponent(tree: FsTree, name: string, path: string) {

225

const componentDir = `${path}/${name}`;

226

227

// Generate component file

228

tree.write(`${componentDir}/${name}.component.ts`, `

229

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

230

231

@Component({

232

selector: 'app-${name}',

233

templateUrl: './${name}.component.html',

234

styleUrls: ['./${name}.component.css']

235

})

236

export class ${pascalCase(name)}Component {

237

constructor() {}

238

}

239

`);

240

241

// Generate template

242

tree.write(`${componentDir}/${name}.component.html`, `

243

<div class="${name}-container">

244

<h2>${name} works!</h2>

245

</div>

246

`);

247

248

// Generate styles

249

tree.write(`${componentDir}/${name}.component.css`, `

250

.${name}-container {

251

padding: 1rem;

252

}

253

`);

254

255

// Generate test file

256

tree.write(`${componentDir}/${name}.component.spec.ts`, `

257

import { ComponentFixture, TestBed } from '@angular/core/testing';

258

import { ${pascalCase(name)}Component } from './${name}.component';

259

260

describe('${pascalCase(name)}Component', () => {

261

let component: ${pascalCase(name)}Component;

262

let fixture: ComponentFixture<${pascalCase(name)}Component>;

263

264

beforeEach(() => {

265

TestBed.configureTestingModule({

266

declarations: [${pascalCase(name)}Component]

267

});

268

fixture = TestBed.createComponent(${pascalCase(name)}Component);

269

component = fixture.componentInstance;

270

});

271

272

it('should create', () => {

273

expect(component).toBeTruthy();

274

});

275

});

276

`);

277

}

278

279

function pascalCase(str: string): string {

280

return str.charAt(0).toUpperCase() + str.slice(1);

281

}

282

283

// Usage

284

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

285

generateComponent(tree, 'user-profile', 'src/app/components');

286

287

// Apply changes

288

const changes = tree.listChanges();

289

printChanges(changes);

290

flushChanges(tree.root, changes);

291

```

292

293

### File Permissions and Options

294

295

```typescript

296

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

297

298

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

299

300

// Write executable script

301

const scriptOptions: TreeWriteOptions = {

302

mode: 0o755 // rwxr-xr-x

303

};

304

305

tree.write('scripts/build.sh', `#!/bin/bash

306

echo "Building project..."

307

npm run build

308

`, scriptOptions);

309

310

// Or change permissions after writing

311

tree.write('scripts/deploy.sh', '#!/bin/bash\necho "Deploying..."');

312

tree.changePermissions('scripts/deploy.sh', 0o755);

313

314

// Apply changes

315

flushChanges(tree.root, tree.listChanges());

316

```

317

318

## Integration with Code Generation

319

320

The Tree API is commonly used with other @nrwl/tao APIs for comprehensive code generation:

321

322

```typescript

323

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

324

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

325

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

326

327

async function generateLibrary(workspaceRoot: string, libName: string) {

328

const tree = new FsTree(workspaceRoot);

329

const workspaces = new Workspaces(workspaceRoot);

330

331

try {

332

// Read existing workspace configuration

333

const projects = workspaces.readProjectsConfigurations();

334

335

// Generate library files

336

const libPath = `libs/${libName}`;

337

tree.write(`${libPath}/src/index.ts`, `export * from './lib/${libName}';`);

338

tree.write(`${libPath}/src/lib/${libName}.ts`, `

339

export function ${libName}(): string {

340

return '${libName}';

341

}

342

`);

343

344

// Update workspace configuration

345

const updatedProjects = {

346

...projects,

347

projects: {

348

...projects.projects,

349

[libName]: {

350

root: libPath,

351

sourceRoot: `${libPath}/src`,

352

projectType: 'library' as const,

353

targets: {

354

build: {

355

executor: '@nx/js:tsc',

356

options: {

357

outputPath: `dist/${libPath}`,

358

main: `${libPath}/src/index.ts`,

359

tsConfig: `${libPath}/tsconfig.lib.json`

360

}

361

}

362

}

363

}

364

}

365

};

366

367

// Write updated configuration (this would typically be done through workspace APIs)

368

tree.write('workspace.json', JSON.stringify(updatedProjects, null, 2));

369

370

// Apply all changes

371

const changes = tree.listChanges();

372

logger.info(`Generating library '${libName}' with ${changes.length} file operations`);

373

374

flushChanges(tree.root, changes);

375

logger.info(`Library '${libName}' generated successfully`);

376

377

} catch (error) {

378

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

379

throw error;

380

}

381

}

382

```