A Node.js-like standard library for .NET, enabling TypeScript compiled to C# via Tsonic to use familiar APIs for file system, path manipulation, events, and more.
Tsonic compiles TypeScript to C# so code can run on .NET. While the Tsonic Runtime provides JavaScript standard library functionality (console, Math, JSON, etc.), nodejs implements Node.js-inspired APIs like fs, path, and events.
Note: This library is inspired by Node.js APIs but is not an exact replica. It provides similar, familiar APIs that work naturally with .NET while maintaining the Node.js developer experience. APIs may deviate where .NET offers better approaches or where exact Node.js compatibility is impractical.
This repository provides:
- C# Implementation (
nodejs) - A .NET library with Node.js-inspired APIs optimized for .NET - TypeScript Declarations (
.d.tsfiles) - Type definitions for IDE support - Metadata Files (
.metadata.json) - C# semantic information for the Tsonic compiler - Bindings (
.bindings.json) - Maps JavaScript module names to CLR types
npm install --save-dev @tsonic/node-typesdotnet add package nodejsimport * as path from "path";
import * as fs from "fs";
import { EventEmitter } from "events";
// Path operations
const fullPath = path.join(__dirname, "config", "settings.json");
const ext = path.extname(fullPath); // ".json"
const dir = path.dirname(fullPath);
// File system operations
const content = fs.readFileSync("./package.json", "utf-8");
fs.writeFileSync("./output.txt", "Hello from Tsonic!");
// Event handling
class MyEmitter extends EventEmitter {}
const emitter = new MyEmitter();
emitter.on("event", (data) => console.log(data));
emitter.emit("event", "Hello World!");Add to your tsconfig.json or Tsonic configuration:
{
"$schema": "https://tsonic.org/schema/v1.json",
"rootNamespace": "MyApp",
"entryPoint": "src/index.ts",
"dotnet": {
"typeRoots": [
"node_modules/@tsonic/dotnet-types/10.0.0/types",
"../tsonic-runtime/src/Tsonic.Runtime/types",
"node_modules/@tsonic/node-types/types"
],
"packages": [
{ "name": "Tsonic.Runtime", "version": "1.0.0" },
{ "name": "nodejs", "version": "1.0.0" }
]
}
}The Tsonic compiler will:
- Load type definitions from
@tsonic/node-types - Use bindings to map
import "fs"→nodejs.fs - Generate C# code that calls the .NET implementation
- Add NuGet package references automatically
For detailed API coverage compared to official Node.js types, see API Coverage.
Provides utilities for working with file and directory paths.
import * as path from "path";
path.join("/foo", "bar", "baz"); // "/foo/bar/baz"
path.basename("/foo/bar/file.txt"); // "file.txt"
path.extname("index.html"); // ".html"
path.resolve("wwwroot", "static"); // Absolute path
path.isAbsolute("/foo"); // trueAvailable functions:
basename(path, suffix?)- Get the last portion of a pathdirname(path)- Get the directory nameextname(path)- Get the file extensionjoin(...paths)- Join path segmentsnormalize(path)- Normalize a pathresolve(...paths)- Resolve to an absolute pathisAbsolute(path)- Test if path is absoluterelative(from, to)- Get relative pathparse(path)- Parse a path into an objectformat(pathObject)- Format a path from an objectmatchesGlob(path, pattern)- Test glob pattern matchingtoNamespacedPath(path)- Windows namespace prefix (Windows only)
Properties:
sep- Platform-specific path separator (/or\)delimiter- Platform-specific path delimiter (:or;)posix- POSIX path utilitieswin32- Windows path utilities
Synchronous file system operations for reading, writing, and manipulating files and directories.
import * as fs from "fs";
// Read/write files
const data = fs.readFileSync("./config.json", "utf-8");
fs.writeFileSync("./output.txt", "Hello!");
fs.appendFileSync("./log.txt", "New entry\n");
// Directory operations
fs.mkdirSync("./temp", { recursive: true });
const files = fs.readdirSync("./src");
fs.rmdirSync("./temp", { recursive: true });
// File info
const stats = fs.statSync("./package.json");
console.log(stats.size, stats.mtime);
// Other operations
fs.existsSync("./file.txt");
fs.copyFileSync("./src.txt", "./dest.txt");
fs.renameSync("./old.txt", "./new.txt");
fs.unlinkSync("./file.txt");Available functions:
readFileSync(path, encoding?)- Read file contentswriteFileSync(path, data, encoding?)- Write to fileappendFileSync(path, data, encoding?)- Append to fileexistsSync(path)- Check if path existsmkdirSync(path, options?)- Create directoryreaddirSync(path)- Read directory contentsstatSync(path)- Get file/directory statsunlinkSync(path)- Delete filermdirSync(path, options?)- Remove directorycopyFileSync(src, dest)- Copy filerenameSync(oldPath, newPath)- Rename/move file
Node.js EventEmitter for implementing event-driven architectures.
import { EventEmitter } from "events";
class DataStream extends EventEmitter {
processData() {
this.emit("data", { chunk: 1 });
this.emit("end");
}
}
const stream = new DataStream();
stream.on("data", (chunk) => console.log("Data:", chunk));
stream.once("end", () => console.log("Complete"));
stream.processData();Available methods:
on(eventName, listener)- Register event listeneronce(eventName, listener)- Register one-time listeneremit(eventName, ...args)- Trigger eventoff(eventName, listener)/removeListener()- Remove listenerremoveAllListeners(eventName?)- Remove all listenerslisteners(eventName)- Get listener arraylistenerCount(eventName)- Count listenerseventNames()- Get registered event namessetMaxListeners(n)/getMaxListeners()- Listener limitsprependListener()/prependOnceListener()- Add to beginning
TypeScript Source Code
↓
Tsonic Compiler
↓
(reads .d.ts, .metadata.json, .bindings.json)
↓
Generated C# Code
↓
.NET Runtime (NativeAOT)
↓
nodejs (this library)
↓
.NET BCL (File, Path, etc.)
nodejs-clr/
├── src/nodejs/ # C# implementation
│ ├── path.cs # Path module
│ ├── fs.cs # File system module
│ └── EventEmitter.cs # Event emitter
├── types/ # TypeScript declarations
│ ├── path.d.ts # Path type definitions
│ ├── fs.d.ts # FS type definitions
│ ├── events-simple.d.ts # Events type definitions
│ ├── *.metadata.json # CLR metadata
│ ├── nodejs.bindings.json # Module bindings
│ └── index.d.ts # Main entry point
├── tests/nodejs.Tests/ # Unit tests
└── nodejs.sln # Solution file
Bindings (nodejs.bindings.json) map JavaScript imports to C# types:
{
"bindings": {
"path": {
"kind": "module",
"assembly": "nodejs",
"type": "nodejs.path"
}
}
}Metadata (.metadata.json) provides C# semantic information:
{
"assemblyName": "nodejs",
"types": {
"nodejs.path": {
"kind": "class",
"isStatic": true,
"members": {
"join(params string[])": {
"kind": "method",
"isStatic": true
}
}
}
}
}- .NET 10 SDK (or later)
- Node.js 18+ (for npm package)
# Build C# library
dotnet build
# Run tests
dotnet test
# Pack NuGet package
dotnet pack src/nodejs/nodejs.csproj -c Release
# Pack npm package
npm packcd tests/nodejs.Tests
dotnet testImportant: This is not a Node.js compatibility layer. It's a .NET-native standard library inspired by Node.js APIs. Expect differences where .NET offers better approaches or where exact compatibility is impractical.
- Familiar, not identical - APIs follow Node.js conventions but adapt to .NET idioms
- Pragmatic - We deviate from Node.js when .NET offers better solutions
- Performance - Leverages .NET BCL for optimal performance
- NativeAOT first - Designed for ahead-of-time compilation
- Asynchronous operations - Only synchronous methods are implemented currently
- Streams -
ReadStream,WriteStream, etc. - Promises -
fs/promisesmodule - Advanced features - File watchers, advanced stat info, symbolic links
- Buffer - Binary data handling (partially - use
Uint8Arrayinstead) - Process module - Not yet implemented
- File permissions - Limited support on Windows (mode/chmod operations may not work as expected)
- Path separators - Automatically handled by .NET APIs
- Case sensitivity - Follows platform conventions (case-insensitive on Windows)
Contributions are welcome! This project follows the patterns established in tsonic-runtime.
- Create C# implementation in
src/nodejs/ - Add TypeScript declarations in
types/ - Create metadata file (
types/<module>.metadata.json) - Add binding in
types/nodejs.bindings.json - Add reference in
types/index.d.ts - Write tests in
tests/nodejs.Tests/
MIT License - see LICENSE file for details.
- Tsonic - TypeScript to C# compiler
- Tsonic Runtime - JavaScript standard library for .NET
- Documentation: https://tsonic.org
- Issues: https://github.com/tsoniclang/nodejs-clr/issues
- Discussions: https://github.com/tsoniclang/tsonic/discussions