0
# System and Environment Utilities
1
2
Environment detection utilities and system-level helpers for cross-platform compatibility, feature detection, and development tooling.
3
4
## Capabilities
5
6
### Environment Detection Constants
7
8
Pre-computed boolean constants for detecting environment capabilities and features.
9
10
```typescript { .api }
11
/**
12
* True if environment has proper BigInt support
13
*/
14
const hasBigInt: boolean;
15
16
/**
17
* True if environment is CommonJS (Node.js require/exports)
18
*/
19
const hasCjs: boolean;
20
21
/**
22
* True if environment has __dirname available (typically Node.js)
23
*/
24
const hasDirname: boolean;
25
26
/**
27
* True if environment is ESM (ES Module import/export)
28
*/
29
const hasEsm: boolean;
30
31
/**
32
* True if environment has WebAssembly available
33
*/
34
const hasWasm: boolean;
35
36
/**
37
* True if environment has Buffer support (typically Node.js)
38
*/
39
const hasBuffer: boolean;
40
41
/**
42
* True if environment has process object available (typically Node.js)
43
*/
44
const hasProcess: boolean;
45
```
46
47
### Package Detection
48
49
Utilities for detecting package version consistency and import patterns.
50
51
```typescript { .api }
52
/**
53
* Package information constant for @polkadot/util package
54
*/
55
const packageInfo: PackageInfo;
56
57
/**
58
* Package detection warning flag constant
59
*/
60
const POLKADOTJS_DISABLE_ESM_CJS_WARNING_FLAG: string;
61
62
/**
63
* Checks for single package import and dependency version consistency
64
* @param packageInfo - Package information object
65
* @param path - Import path (optional)
66
* @param deps - Dependency package information array (optional)
67
*/
68
function detectPackage(packageInfo: PackageInfo, path?: string, deps?: PackageInfo[]): void;
69
70
interface PackageInfo {
71
name: string;
72
path: string;
73
type: string;
74
version: string;
75
}
76
```
77
78
### Logging Utilities
79
80
Consistent logging interface with debug, log, warn, and error methods.
81
82
```typescript { .api }
83
/**
84
* Creates consistent log interface with debug, log, warn, error methods
85
* @param type - Logger type/name for prefixing messages
86
*/
87
function logger(type: string): Logger;
88
89
/**
90
* Formats values for logging (handles BigInt, Uint8Array, etc.)
91
* @param values - Values to format for logging
92
*/
93
function loggerFormat(...values: unknown[]): unknown[];
94
95
interface Logger {
96
debug: (...values: unknown[]) => void;
97
error: (...values: unknown[]) => void;
98
log: (...values: unknown[]) => void;
99
warn: (...values: unknown[]) => void;
100
}
101
```
102
103
### Asynchronous Utilities
104
105
Helper functions for managing asynchronous operations and execution flow.
106
107
```typescript { .api }
108
/**
109
* Defers operation to next tick with error handling
110
* @param fn - Function to execute on next tick
111
*/
112
function nextTick(fn: () => void): void;
113
114
/**
115
* Wraps async callback function into Promise
116
* @param fn - Callback-based function to promisify
117
*/
118
function promisify<T>(fn: Function): (...args: any[]) => Promise<T>;
119
```
120
121
### Performance Utilities
122
123
Functions for optimization including memoization and lazy evaluation.
124
125
```typescript { .api }
126
/**
127
* Memoizes function with instance-based caching
128
* @param fn - Function to memoize
129
*/
130
function memoize<T extends (...args: any[]) => any>(fn: T): Memoized<T>;
131
132
/**
133
* Creates lazy, on-demand getter for specific value
134
* @param fn - Function that returns the value
135
* @param key - Property key name
136
*/
137
function lazyMethod<T>(fn: () => T, key: string): () => T;
138
139
/**
140
* Creates lazy, on-demand getters for multiple values
141
* @param obj - Object to add lazy methods to
142
* @param methods - Map of method names to value functions
143
*/
144
function lazyMethods<T>(obj: T, methods: Record<string, () => unknown>): T;
145
146
type Memoized<T extends (...args: any[]) => any> = T & {
147
unmemoize: () => void;
148
};
149
```
150
151
### Utility Functions
152
153
General-purpose helper functions for common operations.
154
155
```typescript { .api }
156
/**
157
* Returns input value unchanged (identity function)
158
* @param value - Value to return as-is
159
*/
160
function identity<T>(value: T): T;
161
162
/**
163
* No-operation function (does nothing)
164
*/
165
function noop(): void;
166
167
/**
168
* JSON.stringify with BigInt handling
169
* @param value - Value to stringify
170
* @param replacer - Replacer function (optional)
171
* @param space - Indentation (optional)
172
*/
173
function stringify(value: unknown, replacer?: (key: string, value: unknown) => unknown, space?: string | number): string;
174
```
175
176
## Usage Examples
177
178
**Environment Detection:**
179
180
```typescript
181
import {
182
hasBigInt, hasBuffer, hasWasm, hasCjs, hasEsm, hasProcess
183
} from "@polkadot/util";
184
185
// Feature detection for conditional code paths
186
function detectEnvironment() {
187
console.log("Environment Detection:");
188
console.log(`BigInt support: ${hasBigInt}`);
189
console.log(`Buffer support: ${hasBuffer}`);
190
console.log(`WebAssembly support: ${hasWasm}`);
191
console.log(`CommonJS: ${hasCjs}`);
192
console.log(`ES Modules: ${hasEsm}`);
193
console.log(`Node.js process: ${hasProcess}`);
194
}
195
196
// Conditional polyfills
197
if (!hasBigInt) {
198
console.warn("BigInt not supported, consider using BN.js");
199
}
200
201
// Platform-specific code
202
function getRandomBytes(length: number): Uint8Array {
203
if (hasBuffer && hasProcess) {
204
// Node.js environment
205
const crypto = require('crypto');
206
return new Uint8Array(crypto.randomBytes(length));
207
} else {
208
// Browser environment
209
const array = new Uint8Array(length);
210
crypto.getRandomValues(array);
211
return array;
212
}
213
}
214
```
215
216
**Package Version Detection:**
217
218
```typescript
219
import { packageInfo, detectPackage } from "@polkadot/util";
220
221
// Check for consistent package versions in development
222
const myPackageInfo = {
223
name: '@polkadot/util',
224
version: '13.5.6',
225
path: '/node_modules/@polkadot/util',
226
type: 'esm'
227
};
228
229
const dependencies = [
230
{
231
name: '@polkadot/keyring',
232
version: '13.5.6',
233
path: '/node_modules/@polkadot/keyring',
234
type: 'esm'
235
}
236
];
237
238
// This will warn if versions are inconsistent
239
detectPackage(myPackageInfo, __filename, dependencies);
240
241
// Disable warnings in production
242
if (process.env.NODE_ENV === 'production') {
243
process.env[POLKADOTJS_DISABLE_ESM_CJS_WARNING_FLAG] = '1';
244
}
245
```
246
247
**Logging:**
248
249
```typescript
250
import { logger, loggerFormat } from "@polkadot/util";
251
252
// Create typed logger
253
const log = logger('MyApp');
254
255
// Basic logging
256
log.debug('Debug information');
257
log.log('General information');
258
log.warn('Warning message');
259
log.error('Error occurred');
260
261
// Format complex values for logging
262
const complexData = {
263
bigInt: BigInt('123456789012345678901234567890'),
264
uint8Array: new Uint8Array([1, 2, 3, 4, 5]),
265
nested: { foo: 'bar' }
266
};
267
268
const formatted = loggerFormat(complexData);
269
log.log('Complex data:', formatted);
270
271
// Module-specific loggers
272
const apiLogger = logger('API');
273
const dbLogger = logger('Database');
274
275
apiLogger.log('API request received');
276
dbLogger.error('Database connection failed');
277
```
278
279
**Asynchronous Operations:**
280
281
```typescript
282
import { nextTick, promisify } from "@polkadot/util";
283
284
// Defer operations to next tick
285
function processQueue(items: string[]) {
286
console.log('Processing started');
287
288
items.forEach((item, index) => {
289
nextTick(() => {
290
console.log(`Processing item ${index}: ${item}`);
291
});
292
});
293
294
console.log('Processing scheduled');
295
}
296
297
processQueue(['A', 'B', 'C']);
298
// Output:
299
// Processing started
300
// Processing scheduled
301
// Processing item 0: A
302
// Processing item 1: B
303
// Processing item 2: C
304
305
// Promisify callback-based functions
306
const fs = require('fs');
307
const readFileAsync = promisify(fs.readFile);
308
309
async function readConfig() {
310
try {
311
const data = await readFileAsync('config.json', 'utf8');
312
return JSON.parse(data);
313
} catch (error) {
314
console.error('Failed to read config:', error);
315
return null;
316
}
317
}
318
```
319
320
**Performance Optimization:**
321
322
```typescript
323
import { memoize, lazyMethod, lazyMethods } from "@polkadot/util";
324
325
// Memoize expensive calculations
326
const expensiveCalculation = memoize((n: number): number => {
327
console.log(`Computing factorial of ${n}`);
328
return n <= 1 ? 1 : n * expensiveCalculation(n - 1);
329
});
330
331
console.log(expensiveCalculation(5)); // Computes and caches
332
console.log(expensiveCalculation(5)); // Returns cached result
333
console.log(expensiveCalculation(6)); // Computes 6, reuses cached 5!
334
335
// Clear memoization cache
336
expensiveCalculation.unmemoize();
337
338
// Lazy evaluation for expensive resources
339
class APIClient {
340
constructor(private baseUrl: string) {
341
// Lazy-load heavy dependencies
342
lazyMethods(this, {
343
crypto: () => require('crypto'),
344
httpClient: () => require('axios').create({ baseURL: this.baseUrl }),
345
parser: () => require('xml2js')
346
});
347
}
348
349
// Properties will be created on first access
350
private crypto!: any;
351
private httpClient!: any;
352
private parser!: any;
353
354
async fetchData() {
355
// httpClient is loaded only when first used
356
return this.httpClient.get('/data');
357
}
358
}
359
360
// Single lazy method
361
const getLazyResource = lazyMethod(() => {
362
console.log('Loading expensive resource...');
363
return { data: 'expensive resource' };
364
}, 'resource');
365
366
console.log('Before access');
367
const resource1 = getLazyResource(); // Logs "Loading expensive resource..."
368
const resource2 = getLazyResource(); // Returns cached result
369
console.log(resource1 === resource2); // true
370
```
371
372
**Utility Functions:**
373
374
```typescript
375
import { identity, noop, stringify } from "@polkadot/util";
376
377
// Identity function for functional programming
378
const numbers = [1, 2, 3, 4, 5];
379
const filtered = numbers.filter(identity); // Removes falsy values
380
console.log(filtered); // [1, 2, 3, 4, 5]
381
382
// Use in reduce operations
383
const result = numbers.reduce((acc, val) => acc + val, 0);
384
// vs using identity for passthrough
385
const passthrough = numbers.map(identity); // Returns same array
386
387
// No-op function for optional callbacks
388
function processData(data: string[], callback: () => void = noop) {
389
data.forEach(item => console.log(item));
390
callback(); // Safe to call even if not provided
391
}
392
393
processData(['A', 'B', 'C']); // Uses noop callback
394
processData(['D', 'E', 'F'], () => console.log('Done!')); // Custom callback
395
396
// JSON stringify with BigInt support
397
const data = {
398
id: 123,
399
balance: BigInt('1000000000000000000'),
400
timestamp: new Date(),
401
nested: {
402
value: BigInt('999999999999999999')
403
}
404
};
405
406
const json = stringify(data, null, 2);
407
console.log(json);
408
// {
409
// "id": 123,
410
// "balance": "1000000000000000000",
411
// "timestamp": "2023-12-07T14:30:15.123Z",
412
// "nested": {
413
// "value": "999999999999999999"
414
// }
415
// }
416
417
// Standard JSON.stringify would throw on BigInt
418
try {
419
JSON.stringify(data); // Error: Do not know how to serialize a BigInt
420
} catch (error) {
421
console.error('Standard stringify failed:', error.message);
422
}
423
```
424
425
**Cross-Platform Development:**
426
427
```typescript
428
import { hasBuffer, hasProcess, hasCjs, hasEsm } from "@polkadot/util";
429
430
// Universal module loader
431
function loadModule(name: string) {
432
if (hasCjs) {
433
return require(name);
434
} else if (hasEsm) {
435
return import(name);
436
} else {
437
throw new Error('No module system available');
438
}
439
}
440
441
// Platform-specific implementations
442
class Storage {
443
save(key: string, data: string): void {
444
if (hasProcess && hasBuffer) {
445
// Node.js - use filesystem
446
const fs = require('fs');
447
fs.writeFileSync(`${key}.json`, data);
448
} else {
449
// Browser - use localStorage
450
localStorage.setItem(key, data);
451
}
452
}
453
454
load(key: string): string | null {
455
if (hasProcess && hasBuffer) {
456
// Node.js - read from filesystem
457
const fs = require('fs');
458
try {
459
return fs.readFileSync(`${key}.json`, 'utf8');
460
} catch {
461
return null;
462
}
463
} else {
464
// Browser - use localStorage
465
return localStorage.getItem(key);
466
}
467
}
468
}
469
```
470
471
## Types
472
473
```typescript { .api }
474
interface PackageInfo {
475
name: string;
476
path: string;
477
type: string;
478
version: string;
479
}
480
481
interface Logger {
482
debug: (...values: unknown[]) => void;
483
error: (...values: unknown[]) => void;
484
log: (...values: unknown[]) => void;
485
warn: (...values: unknown[]) => void;
486
}
487
488
type Memoized<T extends (...args: any[]) => any> = T & {
489
unmemoize: () => void;
490
};
491
```