A collection of useful utilities for @polkadot ecosystem with type checking, data conversion, and performance optimization functions
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Environment detection utilities and system-level helpers for cross-platform compatibility, feature detection, and development tooling.
Pre-computed boolean constants for detecting environment capabilities and features.
/**
* True if environment has proper BigInt support
*/
const hasBigInt: boolean;
/**
* True if environment is CommonJS (Node.js require/exports)
*/
const hasCjs: boolean;
/**
* True if environment has __dirname available (typically Node.js)
*/
const hasDirname: boolean;
/**
* True if environment is ESM (ES Module import/export)
*/
const hasEsm: boolean;
/**
* True if environment has WebAssembly available
*/
const hasWasm: boolean;
/**
* True if environment has Buffer support (typically Node.js)
*/
const hasBuffer: boolean;
/**
* True if environment has process object available (typically Node.js)
*/
const hasProcess: boolean;Utilities for detecting package version consistency and import patterns.
/**
* Package information constant for @polkadot/util package
*/
const packageInfo: PackageInfo;
/**
* Package detection warning flag constant
*/
const POLKADOTJS_DISABLE_ESM_CJS_WARNING_FLAG: string;
/**
* Checks for single package import and dependency version consistency
* @param packageInfo - Package information object
* @param path - Import path (optional)
* @param deps - Dependency package information array (optional)
*/
function detectPackage(packageInfo: PackageInfo, path?: string, deps?: PackageInfo[]): void;
interface PackageInfo {
name: string;
path: string;
type: string;
version: string;
}Consistent logging interface with debug, log, warn, and error methods.
/**
* Creates consistent log interface with debug, log, warn, error methods
* @param type - Logger type/name for prefixing messages
*/
function logger(type: string): Logger;
/**
* Formats values for logging (handles BigInt, Uint8Array, etc.)
* @param values - Values to format for logging
*/
function loggerFormat(...values: unknown[]): unknown[];
interface Logger {
debug: (...values: unknown[]) => void;
error: (...values: unknown[]) => void;
log: (...values: unknown[]) => void;
warn: (...values: unknown[]) => void;
}Helper functions for managing asynchronous operations and execution flow.
/**
* Defers operation to next tick with error handling
* @param fn - Function to execute on next tick
*/
function nextTick(fn: () => void): void;
/**
* Wraps async callback function into Promise
* @param fn - Callback-based function to promisify
*/
function promisify<T>(fn: Function): (...args: any[]) => Promise<T>;Functions for optimization including memoization and lazy evaluation.
/**
* Memoizes function with instance-based caching
* @param fn - Function to memoize
*/
function memoize<T extends (...args: any[]) => any>(fn: T): Memoized<T>;
/**
* Creates lazy, on-demand getter for specific value
* @param fn - Function that returns the value
* @param key - Property key name
*/
function lazyMethod<T>(fn: () => T, key: string): () => T;
/**
* Creates lazy, on-demand getters for multiple values
* @param obj - Object to add lazy methods to
* @param methods - Map of method names to value functions
*/
function lazyMethods<T>(obj: T, methods: Record<string, () => unknown>): T;
type Memoized<T extends (...args: any[]) => any> = T & {
unmemoize: () => void;
};General-purpose helper functions for common operations.
/**
* Returns input value unchanged (identity function)
* @param value - Value to return as-is
*/
function identity<T>(value: T): T;
/**
* No-operation function (does nothing)
*/
function noop(): void;
/**
* JSON.stringify with BigInt handling
* @param value - Value to stringify
* @param replacer - Replacer function (optional)
* @param space - Indentation (optional)
*/
function stringify(value: unknown, replacer?: (key: string, value: unknown) => unknown, space?: string | number): string;Environment Detection:
import {
hasBigInt, hasBuffer, hasWasm, hasCjs, hasEsm, hasProcess
} from "@polkadot/util";
// Feature detection for conditional code paths
function detectEnvironment() {
console.log("Environment Detection:");
console.log(`BigInt support: ${hasBigInt}`);
console.log(`Buffer support: ${hasBuffer}`);
console.log(`WebAssembly support: ${hasWasm}`);
console.log(`CommonJS: ${hasCjs}`);
console.log(`ES Modules: ${hasEsm}`);
console.log(`Node.js process: ${hasProcess}`);
}
// Conditional polyfills
if (!hasBigInt) {
console.warn("BigInt not supported, consider using BN.js");
}
// Platform-specific code
function getRandomBytes(length: number): Uint8Array {
if (hasBuffer && hasProcess) {
// Node.js environment
const crypto = require('crypto');
return new Uint8Array(crypto.randomBytes(length));
} else {
// Browser environment
const array = new Uint8Array(length);
crypto.getRandomValues(array);
return array;
}
}Package Version Detection:
import { packageInfo, detectPackage } from "@polkadot/util";
// Check for consistent package versions in development
const myPackageInfo = {
name: '@polkadot/util',
version: '13.5.6',
path: '/node_modules/@polkadot/util',
type: 'esm'
};
const dependencies = [
{
name: '@polkadot/keyring',
version: '13.5.6',
path: '/node_modules/@polkadot/keyring',
type: 'esm'
}
];
// This will warn if versions are inconsistent
detectPackage(myPackageInfo, __filename, dependencies);
// Disable warnings in production
if (process.env.NODE_ENV === 'production') {
process.env[POLKADOTJS_DISABLE_ESM_CJS_WARNING_FLAG] = '1';
}Logging:
import { logger, loggerFormat } from "@polkadot/util";
// Create typed logger
const log = logger('MyApp');
// Basic logging
log.debug('Debug information');
log.log('General information');
log.warn('Warning message');
log.error('Error occurred');
// Format complex values for logging
const complexData = {
bigInt: BigInt('123456789012345678901234567890'),
uint8Array: new Uint8Array([1, 2, 3, 4, 5]),
nested: { foo: 'bar' }
};
const formatted = loggerFormat(complexData);
log.log('Complex data:', formatted);
// Module-specific loggers
const apiLogger = logger('API');
const dbLogger = logger('Database');
apiLogger.log('API request received');
dbLogger.error('Database connection failed');Asynchronous Operations:
import { nextTick, promisify } from "@polkadot/util";
// Defer operations to next tick
function processQueue(items: string[]) {
console.log('Processing started');
items.forEach((item, index) => {
nextTick(() => {
console.log(`Processing item ${index}: ${item}`);
});
});
console.log('Processing scheduled');
}
processQueue(['A', 'B', 'C']);
// Output:
// Processing started
// Processing scheduled
// Processing item 0: A
// Processing item 1: B
// Processing item 2: C
// Promisify callback-based functions
const fs = require('fs');
const readFileAsync = promisify(fs.readFile);
async function readConfig() {
try {
const data = await readFileAsync('config.json', 'utf8');
return JSON.parse(data);
} catch (error) {
console.error('Failed to read config:', error);
return null;
}
}Performance Optimization:
import { memoize, lazyMethod, lazyMethods } from "@polkadot/util";
// Memoize expensive calculations
const expensiveCalculation = memoize((n: number): number => {
console.log(`Computing factorial of ${n}`);
return n <= 1 ? 1 : n * expensiveCalculation(n - 1);
});
console.log(expensiveCalculation(5)); // Computes and caches
console.log(expensiveCalculation(5)); // Returns cached result
console.log(expensiveCalculation(6)); // Computes 6, reuses cached 5!
// Clear memoization cache
expensiveCalculation.unmemoize();
// Lazy evaluation for expensive resources
class APIClient {
constructor(private baseUrl: string) {
// Lazy-load heavy dependencies
lazyMethods(this, {
crypto: () => require('crypto'),
httpClient: () => require('axios').create({ baseURL: this.baseUrl }),
parser: () => require('xml2js')
});
}
// Properties will be created on first access
private crypto!: any;
private httpClient!: any;
private parser!: any;
async fetchData() {
// httpClient is loaded only when first used
return this.httpClient.get('/data');
}
}
// Single lazy method
const getLazyResource = lazyMethod(() => {
console.log('Loading expensive resource...');
return { data: 'expensive resource' };
}, 'resource');
console.log('Before access');
const resource1 = getLazyResource(); // Logs "Loading expensive resource..."
const resource2 = getLazyResource(); // Returns cached result
console.log(resource1 === resource2); // trueUtility Functions:
import { identity, noop, stringify } from "@polkadot/util";
// Identity function for functional programming
const numbers = [1, 2, 3, 4, 5];
const filtered = numbers.filter(identity); // Removes falsy values
console.log(filtered); // [1, 2, 3, 4, 5]
// Use in reduce operations
const result = numbers.reduce((acc, val) => acc + val, 0);
// vs using identity for passthrough
const passthrough = numbers.map(identity); // Returns same array
// No-op function for optional callbacks
function processData(data: string[], callback: () => void = noop) {
data.forEach(item => console.log(item));
callback(); // Safe to call even if not provided
}
processData(['A', 'B', 'C']); // Uses noop callback
processData(['D', 'E', 'F'], () => console.log('Done!')); // Custom callback
// JSON stringify with BigInt support
const data = {
id: 123,
balance: BigInt('1000000000000000000'),
timestamp: new Date(),
nested: {
value: BigInt('999999999999999999')
}
};
const json = stringify(data, null, 2);
console.log(json);
// {
// "id": 123,
// "balance": "1000000000000000000",
// "timestamp": "2023-12-07T14:30:15.123Z",
// "nested": {
// "value": "999999999999999999"
// }
// }
// Standard JSON.stringify would throw on BigInt
try {
JSON.stringify(data); // Error: Do not know how to serialize a BigInt
} catch (error) {
console.error('Standard stringify failed:', error.message);
}Cross-Platform Development:
import { hasBuffer, hasProcess, hasCjs, hasEsm } from "@polkadot/util";
// Universal module loader
function loadModule(name: string) {
if (hasCjs) {
return require(name);
} else if (hasEsm) {
return import(name);
} else {
throw new Error('No module system available');
}
}
// Platform-specific implementations
class Storage {
save(key: string, data: string): void {
if (hasProcess && hasBuffer) {
// Node.js - use filesystem
const fs = require('fs');
fs.writeFileSync(`${key}.json`, data);
} else {
// Browser - use localStorage
localStorage.setItem(key, data);
}
}
load(key: string): string | null {
if (hasProcess && hasBuffer) {
// Node.js - read from filesystem
const fs = require('fs');
try {
return fs.readFileSync(`${key}.json`, 'utf8');
} catch {
return null;
}
} else {
// Browser - use localStorage
return localStorage.getItem(key);
}
}
}interface PackageInfo {
name: string;
path: string;
type: string;
version: string;
}
interface Logger {
debug: (...values: unknown[]) => void;
error: (...values: unknown[]) => void;
log: (...values: unknown[]) => void;
warn: (...values: unknown[]) => void;
}
type Memoized<T extends (...args: any[]) => any> = T & {
unmemoize: () => void;
};Install with Tessl CLI
npx tessl i tessl/npm-polkadot--util