Missing ECMAScript module utils for Node.js
npx @tessl/cli install tessl/npm-mlly@1.8.0mlly provides essential ECMAScript Module (ESM) utilities for Node.js that fill gaps in the evolving ESM ecosystem. It offers comprehensive module resolution capabilities respecting the ECMAScript Resolver algorithm with support for custom extensions and conditions, syntax analysis tools to detect ESM/CommonJS usage and validate Node.js imports, import/export parsing with regex-based static analysis for finding and parsing import/export statements, CommonJS context creation for missing utilities like __dirname and require in ESM, module evaluation capabilities using data: imports with automatic import rewriting and stack-trace support, and various utility functions for path/URL conversion, protocol normalization, and URI sanitization.
npm install mllyimport {
resolve,
findStaticImports,
findExports,
hasESMSyntax,
isValidNodeImport,
createCommonJS,
loadModule,
fileURLToPath
} from "mlly";For CommonJS:
const {
resolve,
findStaticImports,
findExports,
hasESMSyntax,
isValidNodeImport,
createCommonJS,
loadModule,
fileURLToPath
} = require("mlly");import {
resolve,
findStaticImports,
findExports,
hasESMSyntax,
isValidNodeImport,
createCommonJS,
loadModule
} from "mlly";
// Module resolution
const moduleUrl = await resolve("./utils.mjs", { url: import.meta.url });
// Import analysis
const imports = findStaticImports(`import { foo } from "./bar.mjs"`);
console.log(imports[0].specifier); // "./bar.mjs"
// Export analysis
const exports = findExports(`export const hello = "world"; export default 42;`);
console.log(exports.map(exp => exp.names).flat()); // ["hello", "default"]
// Syntax detection
const isESM = hasESMSyntax(`export const hello = "world"`); // true
const canImport = await isValidNodeImport("some-package");
// CommonJS context in ESM
const { __dirname, __filename, require } = createCommonJS(import.meta.url);
// Module evaluation
const module = await loadModule("./config.json", { url: import.meta.url });mlly is built around several key components:
ESM-compliant module resolution with support for custom conditions, extensions, and multiple search paths. Handles Node.js built-ins, file system paths, and various URL protocols.
function resolve(id: string, options?: ResolveOptions): Promise<string>;
function resolveSync(id: string, options?: ResolveOptions): string;
interface ResolveOptions {
url?: string | URL | (string | URL)[];
extensions?: string[];
conditions?: string[];
}Fast regex-based static analysis for finding and parsing ECMAScript import and export statements. Supports static imports, dynamic imports, type imports, and all export patterns.
function findStaticImports(code: string): StaticImport[];
function findDynamicImports(code: string): DynamicImport[];
function findExports(code: string): ESMExport[];
function parseStaticImport(matched: StaticImport | TypeImport): ParsedStaticImport;
function findExportNames(code: string): string[];
function resolveModuleExportNames(id: string, options?: ResolveOptions): Promise<string[]>;
interface StaticImport {
type: "static";
code: string;
start: number;
end: number;
imports: string;
specifier: string;
}Utilities for detecting ECMAScript module syntax, CommonJS syntax, and validating whether imports are safe for dynamic import() calls in Node.js.
function hasESMSyntax(code: string, opts?: DetectSyntaxOptions): boolean;
function hasCJSSyntax(code: string, opts?: DetectSyntaxOptions): boolean;
function detectSyntax(code: string, opts?: DetectSyntaxOptions): { hasESM: boolean; hasCJS: boolean; isMixed: boolean };
function isValidNodeImport(id: string, options?: ValidNodeImportOptions): Promise<boolean>;
interface DetectSyntaxOptions {
stripComments?: boolean;
}Safe module evaluation using data: URLs with automatic import resolution and stack trace preservation. Includes transformation utilities for JSON modules and import.meta.url rewriting.
function loadModule(id: string, options?: EvaluateOptions): Promise<any>;
function evalModule(code: string, options?: EvaluateOptions): Promise<any>;
function transformModule(code: string, options?: EvaluateOptions): Promise<string>;
function resolveImports(code: string, options?: EvaluateOptions): Promise<string>;
interface EvaluateOptions extends ResolveOptions {
url?: string;
}Utilities for creating CommonJS-compatible context within ECMAScript modules, providing __dirname, __filename, and require functionality.
function createCommonJS(url: string): CommonjsContext;
function interopDefault(sourceModule: any, opts?: { preferNamespace?: boolean }): any;
interface CommonjsContext {
__filename: string;
__dirname: string;
require: NodeRequire;
}Core utilities for path/URL conversion, protocol handling, URI sanitization, and Node.js built-in detection. Cross-platform file system path normalization.
function fileURLToPath(id: string | URL): string;
function pathToFileURL(id: string | URL): string;
function isNodeBuiltin(id?: string): boolean;
function loadURL(url: string): Promise<string>;
function toDataURL(code: string): string;
function normalizeid(id: string): string;
function sanitizeURIComponent(name?: string, replacement?: string): string;
function sanitizeFilePath(filePath?: string): string;
function getProtocol(id: string): string | undefined;interface ResolveOptions {
url?: string | URL | (string | URL)[];
extensions?: string[];
conditions?: string[];
}
interface ESMImport {
type: "static" | "dynamic";
code: string;
start: number;
end: number;
}
interface StaticImport extends ESMImport {
type: "static";
imports: string;
specifier: string;
}
interface ParsedStaticImport extends StaticImport {
defaultImport?: string;
namespacedImport?: string;
namedImports?: { [name: string]: string };
}
interface DynamicImport extends ESMImport {
type: "dynamic";
expression: string;
}
interface TypeImport extends Omit<ESMImport, "type"> {
type: "type";
imports: string;
specifier: string;
}
interface ESMExport {
type: "declaration" | "named" | "default" | "star";
code: string;
start: number;
end: number;
name?: string;
names: string[];
specifier?: string;
}
interface ValidNodeImportOptions extends ResolveOptions {
code?: string;
allowedProtocols?: Array<string>;
stripComments?: boolean;
}