CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-nx--devkit

The Nx Devkit provides utilities for creating custom generators, executors, and plugins to extend the Nx build system for different technologies and use cases.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

utilities.mddocs/

Utility Functions

General utility functions for string manipulation, path operations, naming conventions, workspace layout management, and common development tasks.

Capabilities

Naming Utilities

Generate various naming conventions from a base name for consistent file and variable naming.

/**
 * Generate different naming conventions from a base name
 * @param name - Base name to generate variations from
 * @returns Object with different naming conventions
 */
function names(name: string): {
  /** Original name */
  name: string;
  /** PascalCase class name */
  className: string;
  /** camelCase property name */
  propertyName: string;
  /** CONSTANT_CASE constant name */
  constantName: string;
  /** kebab-case file name */
  fileName: string;
};

Usage Examples:

import { names } from "@nx/devkit";

function createComponent(componentName: string) {
  const nameVariations = names(componentName);
  
  console.log(nameVariations);
  // Input: "user-profile"
  // Output: {
  //   name: "user-profile",
  //   className: "UserProfile", 
  //   propertyName: "userProfile",
  //   constantName: "USER_PROFILE",
  //   fileName: "user-profile"
  // }
  
  // Use in templates
  const templateVars = {
    ...nameVariations,
    // Template will use: <%= className %>, <%= propertyName %>, etc.
  };
}

Path Utilities

Utilities for working with file paths, calculating relative paths, and handling cross-platform path operations.

/**
 * Calculate relative path from project directory to workspace root
 * @param fullPathToDir - Full path to directory
 * @returns Relative path string (e.g., "../.." or "../../..")
 */
function offsetFromRoot(fullPathToDir: string): string;

/**
 * Join path fragments in a cross-platform way
 * @param fragments - Path segments to join
 * @returns Joined path string
 */
function joinPathFragments(...fragments: string[]): string;

/**
 * Normalize path separators for current platform
 * @param osSpecificPath - Path with OS-specific separators
 * @returns Normalized path string
 */
function normalizePath(osSpecificPath: string): string;

/**
 * Workspace root directory path
 */
const workspaceRoot: string;

Usage Examples:

import { 
  offsetFromRoot, 
  joinPathFragments, 
  normalizePath, 
  workspaceRoot 
} from "@nx/devkit";

function generateProjectFiles(projectRoot: string) {
  // Calculate relative path to workspace root
  const rootOffset = offsetFromRoot(projectRoot);
  console.log(`From ${projectRoot} to root: ${rootOffset}`);
  // "libs/my-lib" → "../../"
  // "apps/my-app/src" → "../../../"
  
  // Join path fragments safely
  const configPath = joinPathFragments(projectRoot, "src", "config", "settings.json");
  console.log(`Config path: ${configPath}`);
  // "libs/my-lib/src/config/settings.json"
  
  // Normalize paths from different sources
  const windowsPath = "libs\\my-lib\\src\\index.ts";
  const normalizedPath = normalizePath(windowsPath);
  console.log(`Normalized: ${normalizedPath}`);
  // "libs/my-lib/src/index.ts"
  
  // Use workspace root for absolute paths
  const absoluteProjectPath = joinPathFragments(workspaceRoot, projectRoot);
  console.log(`Absolute project path: ${absoluteProjectPath}`);
}

String Manipulation

Advanced string manipulation utilities for applying changes and transformations.

/**
 * Apply a series of changes to a string
 * @param text - Original text
 * @param changes - Array of changes to apply
 * @returns Modified text with all changes applied
 */
function applyChangesToString(
  text: string, 
  changes: StringChange[]
): string;

/**
 * Remove leading indentation from template strings
 * @param strings - Template string parts
 * @param values - Template values
 * @returns String with consistent indentation removed
 */
function stripIndents(strings: TemplateStringsArray, ...values: any[]): string;

/**
 * String change operation
 */
type StringChange = StringInsertion | StringDeletion;

/**
 * Insert text at specific position
 */
interface StringInsertion {
  type: ChangeType.Insert;
  index: number;
  text: string;
}

/**
 * Delete text from specific range
 */
interface StringDeletion {
  type: ChangeType.Delete;
  start: number;
  length: number;
}

enum ChangeType {
  Insert = "insert",
  Delete = "delete"
}

Usage Examples:

import { 
  applyChangesToString, 
  stripIndents,
  ChangeType,
  StringChange 
} from "@nx/devkit";

function modifySourceCode() {
  const originalCode = `
    function hello() {
      console.log("Hello");
    }
  `;
  
  // Define changes to apply
  const changes: StringChange[] = [
    {
      type: ChangeType.Insert,
      index: originalCode.indexOf('"Hello"'),
      text: 'name: string, '
    },
    {
      type: ChangeType.Insert, 
      index: originalCode.indexOf('"Hello"') + 7,
      text: ', ${name}'
    }
  ];
  
  // Apply changes
  const modifiedCode = applyChangesToString(originalCode, changes);
  console.log(modifiedCode);
  
  // Use stripIndents for clean template strings
  const template = stripIndents`
    export class ${className} {
      constructor(private name: string) {}
      
      greet(): string {
        return \`Hello, \${this.name}!\`;
      }
    }
  `;
  
  console.log(template); // No leading indentation
}

JSON Utilities

Low-level JSON parsing and serialization utilities for direct file system operations.

/**
 * Parse JSON string with comment support and error handling
 * @param input - JSON string to parse
 * @param options - Parsing options
 * @returns Parsed object
 */
function parseJson<T = any>(input: string, options?: JsonParseOptions): T;

/**
 * Serialize object to JSON string with formatting
 * @param input - Object to serialize
 * @param options - Serialization options
 * @returns Formatted JSON string
 */
function serializeJson<T = any>(
  input: T, 
  options?: JsonSerializeOptions
): string;

/**
 * Remove comments from JSON string
 * @param text - JSON string with comments
 * @returns Clean JSON string
 */
function stripJsonComments(text: string): string;

/**
 * Read and parse JSON file from disk
 * @param path - File path
 * @returns Parsed JSON object
 */
function readJsonFile<T = any>(path: string): T;

/**
 * Write object to JSON file on disk
 * @param path - File path  
 * @param data - Object to write
 */
function writeJsonFile<T = any>(path: string, data: T): void;

interface JsonParseOptions {
  /** Allow trailing commas */
  allowTrailingComma?: boolean;
  /** Expect comments in JSON */
  expectComments?: boolean;
  /** Disable comments */
  disallowComments?: boolean;
}

interface JsonSerializeOptions {
  /** Number of spaces for indentation */
  spaces?: number;
  /** Replacer function for custom serialization */
  replacer?: (key: string, value: any) => any;
}

Usage Examples:

import { 
  parseJson, 
  serializeJson, 
  stripJsonComments,
  readJsonFile,
  writeJsonFile 
} from "@nx/devkit";

function processJsonFiles() {
  // Parse JSON with comments
  const jsonWithComments = `{
    // Project configuration
    "name": "my-project",
    /* Dependencies */
    "dependencies": {
      "react": "^18.0.0", // Latest React
    }
  }`;
  
  const parsed = parseJson(jsonWithComments, { expectComments: true });
  console.log(parsed);
  
  // Remove comments from JSON string
  const cleanJson = stripJsonComments(jsonWithComments);
  console.log("Clean JSON:", cleanJson);
  
  // Serialize with formatting
  const formatted = serializeJson(parsed, { spaces: 2 });
  console.log("Formatted:", formatted);
  
  // Read/write JSON files directly
  const packageJson = readJsonFile("package.json");
  packageJson.scripts = { ...packageJson.scripts, build: "nx build" };
  writeJsonFile("package.json", packageJson);
}

Workspace Layout

Manage workspace directory structure and understand project organization patterns.

/**
 * Get workspace layout configuration including apps and libs directories
 * @param tree - File system tree
 * @returns Workspace layout configuration
 */
function getWorkspaceLayout(tree: Tree): {
  appsDir: string;
  libsDir: string;
  standaloneAsDefault: boolean;
};

/**
 * Extract layout directory information from a path
 * @param directory - Directory path to analyze
 * @returns Layout directory components
 */
function extractLayoutDirectory(directory?: string): {
  layoutDirectory: string | null;
  projectDirectory?: string;
};

/**
 * Default workspace layout configuration
 */
const workspaceLayout: {
  appsDir: string;
  libsDir: string;
};

Usage Examples:

import { 
  Tree,
  getWorkspaceLayout, 
  extractLayoutDirectory,
  workspaceLayout 
} from "@nx/devkit";

function organizeProject(tree: Tree, options: { 
  name: string; 
  directory?: string; 
  projectType: "application" | "library" 
}) {
  // Get current workspace layout
  const layout = getWorkspaceLayout(tree);
  console.log(`Apps directory: ${layout.appsDir}`);    // "apps"
  console.log(`Libs directory: ${layout.libsDir}`);    // "libs"
  
  // Parse directory option
  const { layoutDirectory, projectDirectory } = extractLayoutDirectory(options.directory);
  // Input: "ui/components" → { layoutDirectory: "ui", projectDirectory: "components" }
  
  // Determine final project path
  const baseDir = options.projectType === "application" 
    ? layout.appsDir 
    : layout.libsDir;
    
  let projectPath: string;
  if (layoutDirectory && projectDirectory) {
    projectPath = `${baseDir}/${layoutDirectory}/${projectDirectory}`;
  } else if (options.directory) {
    projectPath = `${baseDir}/${options.directory}`;
  } else {
    projectPath = `${baseDir}/${options.name}`;
  }
  
  console.log(`Final project path: ${projectPath}`);
  
  // Use default layout for fallback
  if (!layout.appsDir) {
    console.log(`Using default apps directory: ${workspaceLayout.appsDir}`);
  }
}

Logging and Output

Structured logging and formatted output utilities for generators and executors.

/**
 * Structured logger with different log levels
 */
const logger: {
  /** Debug level logging (hidden by default) */
  debug(message: string, ...args: any[]): void;
  /** Informational logging */
  info(message: string, ...args: any[]): void;
  /** Warning level logging */
  warn(message: string, ...args: any[]): void;
  /** Error level logging */
  error(message: string, ...args: any[]): void;
  /** Fatal error logging */
  fatal(message: string, ...args: any[]): void;
  /** Log without formatting */
  log(message: string, ...args: any[]): void;
};

/**
 * Formatted output utilities for console display
 */
const output: {
  /** Write formatted output */
  write(str: string): void;
  /** Write line with formatting */
  writeLine(str: string): void;
  /** Add vertical whitespace */
  addVerticalSeparator(): void;
  /** Add horizontal separator */
  addHorizontalSeparator(): void;
  /** Display success message */
  success(message: string): void;
  /** Display error message */
  error(message: string): void;
  /** Display warning message */
  warn(message: string): void;
  /** Display note/info message */
  note(message: string): void;
};

Usage Examples:

import { logger, output } from "@nx/devkit";

export default function myGenerator(tree: Tree, options: any) {
  // Use structured logging
  logger.info(`Generating ${options.name} project...`);
  logger.debug(`Options: ${JSON.stringify(options)}`);
  
  try {
    // Generate files...
    logger.info("Files generated successfully");
    
    // Use formatted output
    output.success(`✓ Created ${options.name} project`);
    output.addVerticalSeparator();
    output.note("Next steps:");
    output.writeLine("  1. Run nx build " + options.name);
    output.writeLine("  2. Run nx test " + options.name);
    
  } catch (error) {
    logger.error("Generation failed:", error.message);
    output.error(`✗ Failed to create ${options.name} project`);
    output.warn("Check the logs for more details");
    throw error;
  }
}

Cache and Performance

Utilities for working with Nx's caching system and performance optimization.

/**
 * Cache directory path
 */
const cacheDir: string;

/**
 * Check if Nx daemon is enabled and running
 * @returns Whether daemon is enabled
 */
function isDaemonEnabled(): boolean;

/**
 * Hash an array of values for cache key generation
 * @param values - Array of values to hash
 * @returns Hash string
 */
function hashArray(values: any[]): string;

Usage Examples:

import { cacheDir, isDaemonEnabled, hashArray } from "@nx/devkit";
import { existsSync, readFileSync } from "fs";
import { join } from "path";

function checkCacheStatus() {
  // Check cache directory
  console.log(`Cache directory: ${cacheDir}`);
  
  if (existsSync(cacheDir)) {
    console.log("Cache directory exists");
    
    // Check cache contents
    const lockFilePath = join(cacheDir, "d", "daemon.lock");
    if (existsSync(lockFilePath)) {
      console.log("Daemon lock file found");
    }
  }
  
  // Check if daemon is running
  const daemonEnabled = isDaemonEnabled();
  console.log(`Daemon enabled: ${daemonEnabled}`);
  
  if (daemonEnabled) {
    console.log("Using Nx daemon for better performance");
  } else {
    console.log("Running without daemon (slower but more reliable)");
  }
  
  // Generate cache keys using hash function
  const cacheInputs = ["src/**/*.ts", "package.json", process.env.NODE_ENV];
  const cacheKey = hashArray(cacheInputs);
  console.log(`Cache key: ${cacheKey}`);
}

Framework Conversion

Convert between Nx and other framework conventions.

/**
 * Convert Nx generator to Angular DevKit schematic
 * @param generator - Nx generator function
 * @param skipWritingConfigInOldFormat - Skip legacy config format
 * @returns Angular DevKit schematic
 */
function convertNxGenerator<T = any>(
  generator: Generator<T>,
  skipWritingConfigInOldFormat?: boolean
): any;

/**
 * Convert Nx executor to Angular DevKit builder
 * @param executor - Nx executor function
 * @returns Angular DevKit builder
 */
function convertNxExecutor(executor: Executor): any;

Usage Examples:

import { convertNxGenerator, convertNxExecutor, Generator, Executor } from "@nx/devkit";

// Convert Nx generator for use in Angular CLI
const myGenerator: Generator = (tree, options) => {
  // Nx generator implementation
};

const angularSchematic = convertNxGenerator(myGenerator);

// Convert Nx executor for use in Angular CLI  
const myExecutor: Executor = (options, context) => {
  // Nx executor implementation
  return Promise.resolve({ success: true });
};

const angularBuilder = convertNxExecutor(myExecutor);

// Export for Angular CLI collections
export { angularSchematic as mySchematic, angularBuilder as myBuilder };

Install with Tessl CLI

npx tessl i tessl/npm-nx--devkit

docs

executors.md

generators.md

index.md

package-management.md

plugin-development.md

project-graph.md

tree-operations.md

utilities.md

workspace-configuration.md

tile.json