npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

goodscript

v0.13.0

Published

GoodScript compiler - TypeScript to native code

Readme

GoodScript Compiler v0.13.0

Complete TypeScript-to-C++/TypeScript compiler with binary compilation support, comprehensive runtime library, and TypeScript type definitions.

Installation

# Install globally
npm install -g goodscript

# Or use with pnpm
pnpm add -g goodscript

Requirements:

  • Node.js v18+ (for all features)
  • Zig (optional, only needed for --gsCompile to create native binaries)

Why Zig is Optional

GoodScript takes a modular approach similar to Rust's architecture:

  • Core compiler (Node.js only): Validates GoodScript restrictions and generates C++ code
  • Binary compilation (requires Zig): Compiles generated C++ to native executables

This design offers several advantages:

  • Lightweight installation: Package stays small (<5MB) without bundling Zig (~50-80MB)
  • 🎯 Progressive enhancement: Start with validation/C++ generation, add Zig when you need binaries
  • 🔧 Flexibility: Use your preferred Zig version or system package manager
  • 📦 Separation of concerns: Compiler and build toolchain are independent

Without Zig installed:

gsc --gsValidateOnly src/main-gs.ts  # ✅ Works - validates GoodScript restrictions
gsc --gsTarget cpp src/main-gs.ts    # ✅ Works - generates C++ code

With Zig installed:

gsc --gsTarget cpp --gsCompile -o myapp src/main-gs.ts  # ✅ Compiles to native binary

Installing Zig (when you need binary compilation):

# macOS
brew install zig

# Linux
# Download from https://ziglang.org/download/

# Windows
# Download from https://ziglang.org/download/
# Or use: winget install -e --id Zig.Zig

For complete CLI documentation, see CLI.md.

Architecture

TypeScript Source
      ↓
[Phase 1: Frontend]
  - Parser (TypeScript AST)
  - Validator (Good Parts restrictions)
      ↓
[Phase 2: Analysis]
  - Ownership Analyzer (DAG for share<T>)
  - Null Checker (use<T> lifetime safety)
  - Type Signatures (structural typing)
      ↓
[Phase 3: IR Lowering]
  - TypeScript AST → GoodScript IR
  - SSA-based, typed, ownership-aware
      ↓
[Phase 4: Optimizer]
  - Constant folding
  - Dead code elimination
  - Multi-pass optimization
      ↓
[Phase 5: Code Generation]
  - C++ Codegen (ownership/gc mode)
      ↓
[Phase 6: Binary Compilation]
  - Zig compiler integration
  - Cross-platform native binaries
      ↓
Native Binary / TypeScript

Key Improvements over v0.11

  1. Proper IR: SSA-based, explicitly typed intermediate representation
  2. Single source of truth: All type and ownership info in IR
  3. Clean separation: Frontend, IR, optimizer, backend are independent
  4. Multiple backends: C++ (ownership/GC modes), TypeScript
  5. Better optimizations: IR enables dataflow analysis
  6. Binary compilation: End-to-end native binary generation via Zig

Directory Structure

src/
├── ir/              # IR types, builder, visitor, signatures
├── frontend/        # TS parsing, validation, lowering
├── analysis/        # Ownership & null checking
├── backend/         # Code generation (C++, TS)
│   └── cpp/         # C++ codegen + Zig compiler
├── optimizer/       # IR optimization passes
├── compiler.ts      # Main entry point
└── types.ts         # Shared types

Development

# Install dependencies
pnpm install

# Build
pnpm build

# Test (394 tests passing)
pnpm test

# Watch mode
pnpm dev

Status

Phases 1-8 Complete (394 tests passing, 19 skipped)

  • ✅ Phase 1: Frontend (validator, parser)
  • ✅ Phase 2: Analysis (ownership, null checking, type signatures)
  • ✅ Phase 3: IR Lowering (AST → IR, statement types, async context)
  • ✅ Phase 4: Optimizer (constant folding, DCE)
  • ✅ Phase 5: Code Generation (C++, string concat, async/await)
  • ✅ Phase 6: Binary Compilation (Zig + cppcoro integration)
  • ✅ Phase 7: Runtime Library (FileSystem, async/await, Math, JSON, String, Array, Map)
  • ✅ Phase 8: Union Types (T | null, T | undefined)
  • ✅ CLI Tool (gsc command - drop-in replacement for tsc)

Working Features:

  • Core Language: Functions, lambdas, classes, arrays, maps, strings
  • Async/await: Full Promise support with cppcoro
  • Exception handling: try-catch-finally
  • File I/O: FileSystem sync/async API
  • HTTP/HTTPS: HTTP client with automatic OpenSSL detection and BearSSL fallback
  • Math operations: All Math.* methods
  • String operations: Concatenation, slice, includes, split, trim, etc.
  • Type safety: Compile-time constant detection, union types
  • Automatic conversions: Number-to-string in concatenation
  • Built-in globals: console, Math, JSON, Promise, FileSystem, HTTP, HTTPAsync, String, Array, Map

HTTPS Support:

  • macOS/Linux: Uses system OpenSSL (zero overhead, automatic)
  • Windows/minimal systems: Falls back to vendored BearSSL (~300KB)
  • Auto-detection: Compiler detects OpenSSL at build time
  • 100% coverage: HTTPS works on all platforms

Working Examples (11 out of 12):

  • ✅ 03-functions: Lambda captures, higher-order functions
  • ✅ 04-arrays: Array operations, methods, iteration
  • ✅ 05-maps: Map construction, get/set/delete, forEach
  • ✅ 06-strings: String methods and operations
  • ✅ 07-math: All Math methods + string concatenation
  • ✅ 08-exceptions: try-catch-finally error handling
  • ✅ 09-async-await: async/await with Promise handling
  • ✅ 10-file-io: FileSystem sync/async file operations
  • ✅ 11-http-client: HTTP/HTTPS GET requests with async support

In Progress:

  • ⏳ Object literals/structs (for classes example)
  • Watch mode for gsc
  • IDE integration (LSP server)

File Extensions

GoodScript uses -gs.ts and -gs.tsx suffixes (not .gs):

  • math-gs.ts - GoodScript TypeScript file
  • component-gs.tsx - GoodScript TSX/React file

Why this convention?

  • ✅ All TypeScript tooling works out of the box (VSCode, tsc, ESLint, Prettier)
  • ✅ No special IDE plugins needed
  • ✅ Files are valid TypeScript - just import type aliases
  • ✅ Clear intent: -gs signals "follows GoodScript restrictions"
  • ✅ Gradual adoption: mix .ts and -gs.ts files in same project

Example:

// math-gs.ts
import type { own, share, use, integer, integer53 } from 'goodscript';

export function fibonacci(n: integer): integer {
  if (n <= 1) return n;
  return fibonacci(n - 1) + fibonacci(n - 2);
}

export class Buffer {
  data: own<ArrayBuffer>;
  
  constructor(size: integer) {
    this.data = new ArrayBuffer(size);
  }
}

Then compile to native binary:

gsc --target cpp -o myapp src/math-gs.ts
./myapp

Type Definitions

GoodScript provides TypeScript type definitions for ownership types and integers.

Option 1: Explicit imports (recommended)

import type { own, share, use, integer, integer53 } from 'goodscript';

Option 2: Global types (include in tsconfig.json)

{
  "include": [
    "src/**/*",
    "node_modules/goodscript/types/globals.d.ts"
  ]
}

See types/README.md for complete type documentation.

TypeScript/JavaScript Output

Note: For TypeScript/JavaScript output, just use tsc directly on your -gs.ts or -gs.tsx files. GoodScript files are valid TypeScript - the ownership and integer types are simple aliases:

// In JS/TS mode (semantics only enforced in C++ mode)
type own<T> = T;
type share<T> = T;
type use<T> = T;
type integer = number;    // int32_t in C++, number in JS
type integer53 = number;  // int64_t in C++, safe integer in JS

Integer semantics are only guaranteed in C++ compilation mode.

tsconfig.json Integration

The compiler reads tsconfig.json to auto-configure C++ compilation:

Debug Mode ("sourceMap": true):

{
  "compilerOptions": {
    "sourceMap": true  // Enables -g flag, -O0 (no optimization), #line directives
  }
}
  • Generates debug symbols in C++ binary (-g)
  • Disables optimizations for easier debugging (-O0)
  • Embeds #line directives mapping C++ lines → -gs.ts source lines
  • Stack traces show original TypeScript file and line numbers

Production Mode (no sourceMap or false):

{
  "compilerOptions": {
    "sourceMap": false  // Enables -O3 (full optimization), no #line directives
  }
}
  • Maximum optimizations (-O3)
  • Smaller binary size
  • Faster execution
  • No source location tracking

Override with CLI flags:

gsc --debug src/main-gs.ts       # Force debug mode with source maps
gsc --optimize 3 src/main-gs.ts  # Force optimization level

How Source Maps Work:

When sourceMap: true, the compiler embeds C preprocessor #line directives:

// Generated C++ code
#line 1 "/path/to/math-gs.ts"
double add(double a, double b) {
#line 2 "/path/to/math-gs.ts"
  auto result = (a + b);
  return result;
}

This makes debuggers (gdb, lldb) and crash reports show:

math-gs.ts:2  instead of  math.cpp:47

License

Licensed under either of:

  • Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
  • MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)

at your option.