CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-polkadot--util

A collection of useful utilities for @polkadot ecosystem with type checking, data conversion, and performance optimization functions

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

system.mddocs/

System and Environment Utilities

Environment detection utilities and system-level helpers for cross-platform compatibility, feature detection, and development tooling.

Capabilities

Environment Detection Constants

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;

Package Detection

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;
}

Logging Utilities

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;
}

Asynchronous Utilities

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>;

Performance Utilities

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;
};

Utility Functions

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;

Usage Examples

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); // true

Utility 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);
    }
  }
}

Types

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

docs

arrays.md

big-numbers.md

compact.md

data-conversion.md

formatting.md

index.md

objects.md

strings.md

system.md

type-checking.md

tile.json