CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-nx

AI-first build platform designed for monorepo development that provides task orchestration, project graph generation, and CLI tools for managing complex software projects

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

devkit-files.mddocs/

File Operations

File system utilities and virtual file tree operations for generators, code transformations, and automated workspace modifications.

Capabilities

JSON File Operations

High-level utilities for reading, writing, and updating JSON files with type safety.

/**
 * Reads and parses a JSON file
 * @param path - Absolute or workspace-relative path to JSON file
 * @returns Parsed JSON object
 */
function readJsonFile<T = any>(path: string): T;

/**
 * Writes an object to a JSON file with formatting
 * @param path - Absolute or workspace-relative path to JSON file
 * @param data - Object to serialize as JSON
 */
function writeJsonFile<T = any>(path: string, data: T): void;

/**
 * Updates a JSON file using an updater function
 * @param path - Absolute or workspace-relative path to JSON file
 * @param updater - Function that receives current data and returns updated data
 */
function updateJsonFile<T = any>(path: string, updater: (data: T) => T): void;

/**
 * Reads and parses a JSON file from virtual tree
 * @param tree - Virtual file tree
 * @param path - Path to JSON file
 * @returns Parsed JSON object
 */
function readJson<T = any>(tree: Tree, path: string): T;

/**
 * Writes an object to a JSON file in virtual tree
 * @param tree - Virtual file tree
 * @param path - Path to JSON file
 * @param data - Object to serialize as JSON
 */
function writeJson<T = any>(tree: Tree, path: string, data: T): void;

/**
 * Updates a JSON file in virtual tree using an updater function
 * @param tree - Virtual file tree
 * @param path - Path to JSON file
 * @param updater - Function that receives current data and returns updated data
 */
function updateJson<T = any>(tree: Tree, path: string, updater: (data: T) => T): void;

Virtual File Tree

Virtual file system for generators that allows batch operations before writing to disk.

/**
 * Virtual file system interface for generators
 */
interface Tree {
  /** Read file contents as buffer */
  read(filePath: string): Buffer | null;
  /** Read file contents as string with optional encoding */
  read(filePath: string, encoding: BufferEncoding): string | null;
  /** Write file contents from buffer or string */
  write(filePath: string, content: Buffer | string): void;
  /** Check if file exists */
  exists(filePath: string): boolean;
  /** Delete file */
  delete(filePath: string): void;
  /** Rename file */
  rename(from: string, to: string): void;
  /** Check if path is a file */
  isFile(filePath: string): boolean;
  /** List children of directory */
  children(dirPath: string): string[];
  /** Get file change type */
  listChanges(): FileChange[];
}

interface FileChange {
  path: string;
  type: 'CREATE' | 'DELETE' | 'UPDATE';
  content?: Buffer | string;
}

/**
 * Creates a virtual file tree from the current file system
 * @param root - Root directory path (defaults to workspace root)
 * @returns Virtual file tree
 */
function createFsTree(root?: string): FsTree;

/**
 * File system-based tree implementation
 */
declare class FsTree implements Tree {
  constructor(root: string, isVerbose: boolean);
  
  read(filePath: string): Buffer | null;
  read(filePath: string, encoding: BufferEncoding): string | null;
  write(filePath: string, content: Buffer | string): void;
  exists(filePath: string): boolean;
  delete(filePath: string): void;
  rename(from: string, to: string): void;
  isFile(filePath: string): boolean;
  children(dirPath: string): string[];
  listChanges(): FileChange[];
}

File Tree Operations

Functions for applying changes from virtual trees to the actual file system.

/**
 * Applies all changes from a virtual tree to the file system
 * @param tree - Virtual file tree with pending changes
 * @param verbose - Whether to log changes being applied
 */
function flushChanges(tree: Tree, verbose?: boolean): void;

/**
 * Applies string changes to content
 * @param content - Original string content
 * @param changes - Array of string insertions and deletions
 * @returns Modified string content
 */
function applyChangesToString(
  content: string, 
  changes: (StringInsertion | StringDeletion)[]
): string;

interface StringInsertion {
  type: 'insertion';
  index: number;
  text: string;
}

interface StringDeletion {
  type: 'deletion'; 
  start: number;
  length: number;
}

Path Utilities

Utilities for working with file paths in a cross-platform manner.

/**
 * Joins path fragments using the correct separator
 * @param fragments - Path fragments to join
 * @returns Joined path string
 */
function joinPathFragments(...fragments: string[]): string;

/**
 * Normalizes a path by resolving . and .. segments
 * @param path - Path to normalize
 * @returns Normalized path string
 */
function normalizePath(path: string): string;

/**
 * Gets the relative path from one path to another
 * @param from - Source path
 * @param to - Target path
 * @returns Relative path string
 */
function getRelativePath(from: string, to: string): string;

/**
 * Converts Windows-style paths to Unix-style paths
 * @param path - Path to convert
 * @returns Unix-style path
 */
function toUnixPath(path: string): string;

Template Processing

Functions for processing file templates with variable substitution.

/**
 * Generates files from templates with variable substitution
 * @param tree - Virtual file tree
 * @param templatePath - Path to template directory
 * @param targetPath - Target directory for generated files
 * @param substitutions - Variables for template substitution
 */
function generateFiles(
  tree: Tree,
  templatePath: string,
  targetPath: string,
  substitutions: any
): void;

/**
 * Offset from template file names for substitution patterns
 * @param name - Template file name
 * @param substitutions - Variables for substitution
 * @returns Processed file name
 */
function offsetFromRoot(name: string): string;

/**
 * Names utility functions for template processing
 */
interface Names {
  /** Convert to className format */
  className: (name: string) => string;
  /** Convert to propertyName format */
  propertyName: (name: string) => string;
  /** Convert to constantName format */
  constantName: (name: string) => string;
  /** Convert to fileName format */
  fileName: (name: string) => string;
}

const names: Names;

File Filtering and Visiting

Utilities for traversing and filtering files in the workspace.

/**
 * Visits files that are not ignored by .gitignore
 * @param tree - Virtual file tree
 * @param dirPath - Directory to start from (default: workspace root)
 * @param visitor - Function called for each file
 */
function visitNotIgnoredFiles(
  tree: Tree,
  dirPath: string,
  visitor: (filePath: string) => void
): void;

/**
 * Gets all files matching a glob pattern
 * @param tree - Virtual file tree
 * @param pattern - Glob pattern to match
 * @returns Array of matching file paths
 */
function getMatchingFiles(tree: Tree, pattern: string): string[];

/**
 * Checks if a file should be ignored based on .gitignore rules
 * @param filePath - Path to check
 * @param root - Root directory for .gitignore lookup
 * @returns True if file should be ignored
 */
function isIgnored(filePath: string, root?: string): boolean;

Usage Examples

Basic File Operations

import { 
  readJsonFile, 
  writeJsonFile, 
  updateJsonFile,
  logger 
} from "nx/src/devkit-exports";

// Read package.json
const packageJson = readJsonFile('package.json');
logger.info(`Project: ${packageJson.name} v${packageJson.version}`);

// Update package.json
updateJsonFile('package.json', (json) => ({
  ...json,
  scripts: {
    ...json.scripts,
    'custom-build': 'nx build --configuration=production'
  }
}));

// Write new configuration file
writeJsonFile('nx-custom.json', {
  customSetting: 'value',
  options: {
    enableFeature: true
  }
});

Generator File Operations

import { 
  Tree,
  generateFiles,
  formatFiles,
  joinPathFragments,
  names
} from "nx/src/devkit-exports";

interface ComponentGeneratorSchema {
  name: string;
  project: string;
  directory?: string;
}

export default async function componentGenerator(
  tree: Tree,
  options: ComponentGeneratorSchema
) {
  const projectRoot = readProjectConfiguration(tree, options.project).root;
  const componentDir = options.directory 
    ? joinPathFragments(projectRoot, 'src', options.directory)
    : joinPathFragments(projectRoot, 'src');
    
  // Generate component files from templates
  generateFiles(
    tree,
    joinPathFragments(__dirname, 'files'),
    componentDir,
    {
      ...options,
      ...names(options.name),
      template: '' // Remove __template__ from file names
    }
  );
  
  // Update barrel export
  const indexPath = joinPathFragments(componentDir, 'index.ts');
  const componentName = names(options.name).className;
  
  if (tree.exists(indexPath)) {
    const content = tree.read(indexPath, 'utf-8');
    const updatedContent = `${content}\nexport * from './${names(options.name).fileName}';`;
    tree.write(indexPath, updatedContent);
  } else {
    tree.write(indexPath, `export * from './${names(options.name).fileName}';`);
  }
  
  // Format generated files
  await formatFiles(tree);
}

Advanced Tree Operations

import { 
  Tree,
  visitNotIgnoredFiles,
  applyChangesToString,
  StringInsertion
} from "nx/src/devkit-exports";

function addImportToFiles(tree: Tree, importStatement: string) {
  visitNotIgnoredFiles(tree, '', (filePath) => {
    if (!filePath.endsWith('.ts') && !filePath.endsWith('.tsx')) {
      return;
    }
    
    const content = tree.read(filePath, 'utf-8');
    if (!content || content.includes(importStatement)) {
      return;
    }
    
    // Add import at the top of the file
    const changes: StringInsertion[] = [{
      type: 'insertion',
      index: 0,
      text: `${importStatement}\n`
    }];
    
    const updatedContent = applyChangesToString(content, changes);
    tree.write(filePath, updatedContent);
  });
}

// Usage: Add import to all TypeScript files
addImportToFiles(tree, "import { logger } from 'nx/src/devkit-exports';");

Template File Structure

Template files use substitution patterns in file names and content:

files/
├── __name@fileName__.component.ts__template__
├── __name@fileName__.component.spec.ts__template__
└── __name@fileName__.module.ts__template__

Template content example (__name@fileName__.component.ts__template__):

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

@Component({
  selector: '<%= selector %>',
  templateUrl: './<%= fileName %>.component.html',
  styleUrls: ['./<%= fileName %>.component.css']
})
export class <%= className %>Component {
  title = '<%= name %>';
}

Working with Configuration Files

import { Tree, updateJsonFile, readProjectConfiguration } from "nx/src/devkit-exports";

function updateProjectTsConfig(tree: Tree, projectName: string, options: any) {
  const projectConfig = readProjectConfiguration(tree, projectName);
  const tsConfigPath = joinPathFragments(projectConfig.root, 'tsconfig.json');
  
  if (tree.exists(tsConfigPath)) {
    updateJsonFile(tree, tsConfigPath, (tsconfig) => ({
      ...tsconfig,
      compilerOptions: {
        ...tsconfig.compilerOptions,
        ...options.compilerOptions
      }
    }));
  }
}

Install with Tessl CLI

npx tessl i tessl/npm-nx

docs

cli.md

devkit-core.md

devkit-files.md

devkit-tasks.md

generators-executors.md

index.md

plugins.md

tile.json