0
# Utility Functions
1
2
General utility functions for string manipulation, path operations, naming conventions, workspace layout management, and common development tasks.
3
4
## Capabilities
5
6
### Naming Utilities
7
8
Generate various naming conventions from a base name for consistent file and variable naming.
9
10
```typescript { .api }
11
/**
12
* Generate different naming conventions from a base name
13
* @param name - Base name to generate variations from
14
* @returns Object with different naming conventions
15
*/
16
function names(name: string): {
17
/** Original name */
18
name: string;
19
/** PascalCase class name */
20
className: string;
21
/** camelCase property name */
22
propertyName: string;
23
/** CONSTANT_CASE constant name */
24
constantName: string;
25
/** kebab-case file name */
26
fileName: string;
27
};
28
```
29
30
**Usage Examples:**
31
32
```typescript
33
import { names } from "@nx/devkit";
34
35
function createComponent(componentName: string) {
36
const nameVariations = names(componentName);
37
38
console.log(nameVariations);
39
// Input: "user-profile"
40
// Output: {
41
// name: "user-profile",
42
// className: "UserProfile",
43
// propertyName: "userProfile",
44
// constantName: "USER_PROFILE",
45
// fileName: "user-profile"
46
// }
47
48
// Use in templates
49
const templateVars = {
50
...nameVariations,
51
// Template will use: <%= className %>, <%= propertyName %>, etc.
52
};
53
}
54
```
55
56
### Path Utilities
57
58
Utilities for working with file paths, calculating relative paths, and handling cross-platform path operations.
59
60
```typescript { .api }
61
/**
62
* Calculate relative path from project directory to workspace root
63
* @param fullPathToDir - Full path to directory
64
* @returns Relative path string (e.g., "../.." or "../../..")
65
*/
66
function offsetFromRoot(fullPathToDir: string): string;
67
68
/**
69
* Join path fragments in a cross-platform way
70
* @param fragments - Path segments to join
71
* @returns Joined path string
72
*/
73
function joinPathFragments(...fragments: string[]): string;
74
75
/**
76
* Normalize path separators for current platform
77
* @param osSpecificPath - Path with OS-specific separators
78
* @returns Normalized path string
79
*/
80
function normalizePath(osSpecificPath: string): string;
81
82
/**
83
* Workspace root directory path
84
*/
85
const workspaceRoot: string;
86
```
87
88
**Usage Examples:**
89
90
```typescript
91
import {
92
offsetFromRoot,
93
joinPathFragments,
94
normalizePath,
95
workspaceRoot
96
} from "@nx/devkit";
97
98
function generateProjectFiles(projectRoot: string) {
99
// Calculate relative path to workspace root
100
const rootOffset = offsetFromRoot(projectRoot);
101
console.log(`From ${projectRoot} to root: ${rootOffset}`);
102
// "libs/my-lib" → "../../"
103
// "apps/my-app/src" → "../../../"
104
105
// Join path fragments safely
106
const configPath = joinPathFragments(projectRoot, "src", "config", "settings.json");
107
console.log(`Config path: ${configPath}`);
108
// "libs/my-lib/src/config/settings.json"
109
110
// Normalize paths from different sources
111
const windowsPath = "libs\\my-lib\\src\\index.ts";
112
const normalizedPath = normalizePath(windowsPath);
113
console.log(`Normalized: ${normalizedPath}`);
114
// "libs/my-lib/src/index.ts"
115
116
// Use workspace root for absolute paths
117
const absoluteProjectPath = joinPathFragments(workspaceRoot, projectRoot);
118
console.log(`Absolute project path: ${absoluteProjectPath}`);
119
}
120
```
121
122
### String Manipulation
123
124
Advanced string manipulation utilities for applying changes and transformations.
125
126
```typescript { .api }
127
/**
128
* Apply a series of changes to a string
129
* @param text - Original text
130
* @param changes - Array of changes to apply
131
* @returns Modified text with all changes applied
132
*/
133
function applyChangesToString(
134
text: string,
135
changes: StringChange[]
136
): string;
137
138
/**
139
* Remove leading indentation from template strings
140
* @param strings - Template string parts
141
* @param values - Template values
142
* @returns String with consistent indentation removed
143
*/
144
function stripIndents(strings: TemplateStringsArray, ...values: any[]): string;
145
146
/**
147
* String change operation
148
*/
149
type StringChange = StringInsertion | StringDeletion;
150
151
/**
152
* Insert text at specific position
153
*/
154
interface StringInsertion {
155
type: ChangeType.Insert;
156
index: number;
157
text: string;
158
}
159
160
/**
161
* Delete text from specific range
162
*/
163
interface StringDeletion {
164
type: ChangeType.Delete;
165
start: number;
166
length: number;
167
}
168
169
enum ChangeType {
170
Insert = "insert",
171
Delete = "delete"
172
}
173
```
174
175
**Usage Examples:**
176
177
```typescript
178
import {
179
applyChangesToString,
180
stripIndents,
181
ChangeType,
182
StringChange
183
} from "@nx/devkit";
184
185
function modifySourceCode() {
186
const originalCode = `
187
function hello() {
188
console.log("Hello");
189
}
190
`;
191
192
// Define changes to apply
193
const changes: StringChange[] = [
194
{
195
type: ChangeType.Insert,
196
index: originalCode.indexOf('"Hello"'),
197
text: 'name: string, '
198
},
199
{
200
type: ChangeType.Insert,
201
index: originalCode.indexOf('"Hello"') + 7,
202
text: ', ${name}'
203
}
204
];
205
206
// Apply changes
207
const modifiedCode = applyChangesToString(originalCode, changes);
208
console.log(modifiedCode);
209
210
// Use stripIndents for clean template strings
211
const template = stripIndents`
212
export class ${className} {
213
constructor(private name: string) {}
214
215
greet(): string {
216
return \`Hello, \${this.name}!\`;
217
}
218
}
219
`;
220
221
console.log(template); // No leading indentation
222
}
223
```
224
225
### JSON Utilities
226
227
Low-level JSON parsing and serialization utilities for direct file system operations.
228
229
```typescript { .api }
230
/**
231
* Parse JSON string with comment support and error handling
232
* @param input - JSON string to parse
233
* @param options - Parsing options
234
* @returns Parsed object
235
*/
236
function parseJson<T = any>(input: string, options?: JsonParseOptions): T;
237
238
/**
239
* Serialize object to JSON string with formatting
240
* @param input - Object to serialize
241
* @param options - Serialization options
242
* @returns Formatted JSON string
243
*/
244
function serializeJson<T = any>(
245
input: T,
246
options?: JsonSerializeOptions
247
): string;
248
249
/**
250
* Remove comments from JSON string
251
* @param text - JSON string with comments
252
* @returns Clean JSON string
253
*/
254
function stripJsonComments(text: string): string;
255
256
/**
257
* Read and parse JSON file from disk
258
* @param path - File path
259
* @returns Parsed JSON object
260
*/
261
function readJsonFile<T = any>(path: string): T;
262
263
/**
264
* Write object to JSON file on disk
265
* @param path - File path
266
* @param data - Object to write
267
*/
268
function writeJsonFile<T = any>(path: string, data: T): void;
269
270
interface JsonParseOptions {
271
/** Allow trailing commas */
272
allowTrailingComma?: boolean;
273
/** Expect comments in JSON */
274
expectComments?: boolean;
275
/** Disable comments */
276
disallowComments?: boolean;
277
}
278
279
interface JsonSerializeOptions {
280
/** Number of spaces for indentation */
281
spaces?: number;
282
/** Replacer function for custom serialization */
283
replacer?: (key: string, value: any) => any;
284
}
285
```
286
287
**Usage Examples:**
288
289
```typescript
290
import {
291
parseJson,
292
serializeJson,
293
stripJsonComments,
294
readJsonFile,
295
writeJsonFile
296
} from "@nx/devkit";
297
298
function processJsonFiles() {
299
// Parse JSON with comments
300
const jsonWithComments = `{
301
// Project configuration
302
"name": "my-project",
303
/* Dependencies */
304
"dependencies": {
305
"react": "^18.0.0", // Latest React
306
}
307
}`;
308
309
const parsed = parseJson(jsonWithComments, { expectComments: true });
310
console.log(parsed);
311
312
// Remove comments from JSON string
313
const cleanJson = stripJsonComments(jsonWithComments);
314
console.log("Clean JSON:", cleanJson);
315
316
// Serialize with formatting
317
const formatted = serializeJson(parsed, { spaces: 2 });
318
console.log("Formatted:", formatted);
319
320
// Read/write JSON files directly
321
const packageJson = readJsonFile("package.json");
322
packageJson.scripts = { ...packageJson.scripts, build: "nx build" };
323
writeJsonFile("package.json", packageJson);
324
}
325
```
326
327
### Workspace Layout
328
329
Manage workspace directory structure and understand project organization patterns.
330
331
```typescript { .api }
332
/**
333
* Get workspace layout configuration including apps and libs directories
334
* @param tree - File system tree
335
* @returns Workspace layout configuration
336
*/
337
function getWorkspaceLayout(tree: Tree): {
338
appsDir: string;
339
libsDir: string;
340
standaloneAsDefault: boolean;
341
};
342
343
/**
344
* Extract layout directory information from a path
345
* @param directory - Directory path to analyze
346
* @returns Layout directory components
347
*/
348
function extractLayoutDirectory(directory?: string): {
349
layoutDirectory: string | null;
350
projectDirectory?: string;
351
};
352
353
/**
354
* Default workspace layout configuration
355
*/
356
const workspaceLayout: {
357
appsDir: string;
358
libsDir: string;
359
};
360
```
361
362
**Usage Examples:**
363
364
```typescript
365
import {
366
Tree,
367
getWorkspaceLayout,
368
extractLayoutDirectory,
369
workspaceLayout
370
} from "@nx/devkit";
371
372
function organizeProject(tree: Tree, options: {
373
name: string;
374
directory?: string;
375
projectType: "application" | "library"
376
}) {
377
// Get current workspace layout
378
const layout = getWorkspaceLayout(tree);
379
console.log(`Apps directory: ${layout.appsDir}`); // "apps"
380
console.log(`Libs directory: ${layout.libsDir}`); // "libs"
381
382
// Parse directory option
383
const { layoutDirectory, projectDirectory } = extractLayoutDirectory(options.directory);
384
// Input: "ui/components" → { layoutDirectory: "ui", projectDirectory: "components" }
385
386
// Determine final project path
387
const baseDir = options.projectType === "application"
388
? layout.appsDir
389
: layout.libsDir;
390
391
let projectPath: string;
392
if (layoutDirectory && projectDirectory) {
393
projectPath = `${baseDir}/${layoutDirectory}/${projectDirectory}`;
394
} else if (options.directory) {
395
projectPath = `${baseDir}/${options.directory}`;
396
} else {
397
projectPath = `${baseDir}/${options.name}`;
398
}
399
400
console.log(`Final project path: ${projectPath}`);
401
402
// Use default layout for fallback
403
if (!layout.appsDir) {
404
console.log(`Using default apps directory: ${workspaceLayout.appsDir}`);
405
}
406
}
407
```
408
409
### Logging and Output
410
411
Structured logging and formatted output utilities for generators and executors.
412
413
```typescript { .api }
414
/**
415
* Structured logger with different log levels
416
*/
417
const logger: {
418
/** Debug level logging (hidden by default) */
419
debug(message: string, ...args: any[]): void;
420
/** Informational logging */
421
info(message: string, ...args: any[]): void;
422
/** Warning level logging */
423
warn(message: string, ...args: any[]): void;
424
/** Error level logging */
425
error(message: string, ...args: any[]): void;
426
/** Fatal error logging */
427
fatal(message: string, ...args: any[]): void;
428
/** Log without formatting */
429
log(message: string, ...args: any[]): void;
430
};
431
432
/**
433
* Formatted output utilities for console display
434
*/
435
const output: {
436
/** Write formatted output */
437
write(str: string): void;
438
/** Write line with formatting */
439
writeLine(str: string): void;
440
/** Add vertical whitespace */
441
addVerticalSeparator(): void;
442
/** Add horizontal separator */
443
addHorizontalSeparator(): void;
444
/** Display success message */
445
success(message: string): void;
446
/** Display error message */
447
error(message: string): void;
448
/** Display warning message */
449
warn(message: string): void;
450
/** Display note/info message */
451
note(message: string): void;
452
};
453
```
454
455
**Usage Examples:**
456
457
```typescript
458
import { logger, output } from "@nx/devkit";
459
460
export default function myGenerator(tree: Tree, options: any) {
461
// Use structured logging
462
logger.info(`Generating ${options.name} project...`);
463
logger.debug(`Options: ${JSON.stringify(options)}`);
464
465
try {
466
// Generate files...
467
logger.info("Files generated successfully");
468
469
// Use formatted output
470
output.success(`✓ Created ${options.name} project`);
471
output.addVerticalSeparator();
472
output.note("Next steps:");
473
output.writeLine(" 1. Run nx build " + options.name);
474
output.writeLine(" 2. Run nx test " + options.name);
475
476
} catch (error) {
477
logger.error("Generation failed:", error.message);
478
output.error(`✗ Failed to create ${options.name} project`);
479
output.warn("Check the logs for more details");
480
throw error;
481
}
482
}
483
```
484
485
### Cache and Performance
486
487
Utilities for working with Nx's caching system and performance optimization.
488
489
```typescript { .api }
490
/**
491
* Cache directory path
492
*/
493
const cacheDir: string;
494
495
/**
496
* Check if Nx daemon is enabled and running
497
* @returns Whether daemon is enabled
498
*/
499
function isDaemonEnabled(): boolean;
500
501
/**
502
* Hash an array of values for cache key generation
503
* @param values - Array of values to hash
504
* @returns Hash string
505
*/
506
function hashArray(values: any[]): string;
507
```
508
509
**Usage Examples:**
510
511
```typescript
512
import { cacheDir, isDaemonEnabled, hashArray } from "@nx/devkit";
513
import { existsSync, readFileSync } from "fs";
514
import { join } from "path";
515
516
function checkCacheStatus() {
517
// Check cache directory
518
console.log(`Cache directory: ${cacheDir}`);
519
520
if (existsSync(cacheDir)) {
521
console.log("Cache directory exists");
522
523
// Check cache contents
524
const lockFilePath = join(cacheDir, "d", "daemon.lock");
525
if (existsSync(lockFilePath)) {
526
console.log("Daemon lock file found");
527
}
528
}
529
530
// Check if daemon is running
531
const daemonEnabled = isDaemonEnabled();
532
console.log(`Daemon enabled: ${daemonEnabled}`);
533
534
if (daemonEnabled) {
535
console.log("Using Nx daemon for better performance");
536
} else {
537
console.log("Running without daemon (slower but more reliable)");
538
}
539
540
// Generate cache keys using hash function
541
const cacheInputs = ["src/**/*.ts", "package.json", process.env.NODE_ENV];
542
const cacheKey = hashArray(cacheInputs);
543
console.log(`Cache key: ${cacheKey}`);
544
}
545
```
546
547
### Framework Conversion
548
549
Convert between Nx and other framework conventions.
550
551
```typescript { .api }
552
/**
553
* Convert Nx generator to Angular DevKit schematic
554
* @param generator - Nx generator function
555
* @param skipWritingConfigInOldFormat - Skip legacy config format
556
* @returns Angular DevKit schematic
557
*/
558
function convertNxGenerator<T = any>(
559
generator: Generator<T>,
560
skipWritingConfigInOldFormat?: boolean
561
): any;
562
563
/**
564
* Convert Nx executor to Angular DevKit builder
565
* @param executor - Nx executor function
566
* @returns Angular DevKit builder
567
*/
568
function convertNxExecutor(executor: Executor): any;
569
```
570
571
**Usage Examples:**
572
573
```typescript
574
import { convertNxGenerator, convertNxExecutor, Generator, Executor } from "@nx/devkit";
575
576
// Convert Nx generator for use in Angular CLI
577
const myGenerator: Generator = (tree, options) => {
578
// Nx generator implementation
579
};
580
581
const angularSchematic = convertNxGenerator(myGenerator);
582
583
// Convert Nx executor for use in Angular CLI
584
const myExecutor: Executor = (options, context) => {
585
// Nx executor implementation
586
return Promise.resolve({ success: true });
587
};
588
589
const angularBuilder = convertNxExecutor(myExecutor);
590
591
// Export for Angular CLI collections
592
export { angularSchematic as mySchematic, angularBuilder as myBuilder };
593
```