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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@qzlin/ts-cmacro

v1.0.0

Published

Type-checked macro-expanded scripting for hostile JavaScript runtimes - flatten TypeScript modules into a single file

Downloads

24

Readme

ts-cmacro

Type-checked macro-expanded scripting for hostile JavaScript runtimes

ts-cmacro lets you write large, maintainable scripts in TypeScript—with full type checking, IntelliSense, and modular structure—then compile them into a single, flat, top‑level TypeScript file that can be further transpiled to JavaScript for environments which do not support modules, bundlers, IIFE wrappers, or modern JS semantics.

If your runtime only understands:

function main(config) { /* ... */ }

…but you want to author your script like a real project, this tool is for you.


Installation

# Install globally
npm install -g ts-cmacro
# or
pnpm add -g ts-cmacro

# Install as dev dependency
npm install -D ts-cmacro
# or
pnpm add -D ts-cmacro

Usage

CLI

# Basic usage (outputs TypeScript)
ts-cmacro src/main.ts -o dist/script.ts

# Compact output (remove unnecessary whitespace)
ts-cmacro src/main.ts -o dist/script.ts -c

# Output to stdout
ts-cmacro src/main.ts

# Show help
ts-cmacro --help

Programmatic API

import { build } from 'ts-cmacro';

const code = build({
  entry: './src/main.ts',
  compact: true
});

console.log(code);

Why this exists

Many real-world JavaScript runtimes are hostile to modern tooling:

  • No import / export
  • No module loader
  • No filesystem or network I/O
  • No control over the execution context
  • Fragile or non-standard global scope handling

Examples include:

  • Clash Verge / Clash Meta global scripts (boa engine)
  • Surge / Loon / Quantumult X scripts
  • Embedded JS engines (routers, IoT, NAS)
  • WebView / injection-based environments
  • Game scripting engines

In these environments, bundlers break, IIFEs break, and even globalThis may be unreliable.

The only stable contract is:

  • A single script file
  • With top-level declarations
  • And a known entry function (e.g. main)

ts-macro-script embraces this reality instead of fighting it.


Core idea

Treat TypeScript as a macro language, not a module system.

  • import is for humans and tooling, not the runtime
  • The global scope is the linker
  • All complexity is resolved at build time
  • The runtime receives flat, boring, predictable JavaScript (after transpilation)

Think:

  • C + preprocessor + linker
  • Lisp macros
  • Old-school embedded scripting

…but with modern TypeScript ergonomics.


What this tool does

Given an entry file like:

import { buildRules } from "./rules";
import type { ClashConfig } from "./types";

function main(config: ClashConfig) {
  config.rules = buildRules(config.rules ?? []);
  return config;
}

ts-cmacro will:

  1. Parse the TypeScript program using the TypeScript Compiler API
  2. Resolve import dependencies (relative paths only)
  3. Topologically sort source files
  4. Remove all import and export syntax
  5. Concatenate declarations into a single output file

Resulting TypeScript:

function buildRules(old: string[]) {
  return ["DOMAIN-SUFFIX,baidu.com,DIRECT", ...old];
}

function main(config: ClashConfig) {
  config.rules = buildRules(config.rules ?? []);
  return config;
}

Then transpile to JavaScript using your preferred tool:

# Using tsc
tsc dist/script.ts --outFile dist/script.js --target ES2018

# Using esbuild
esbuild dist/script.ts --outfile=dist/script.js --target=es2018

# Using swc
swc dist/script.ts -o dist/script.js

No wrappers. No modules. No runtime helpers.


Non-goals (by design)

This project intentionally does not:

  • ❌ Bundle dependencies like Webpack/Rollup
  • ❌ Emit IIFE or UMD wrappers
  • ❌ Polyfill runtime features
  • ❌ Provide a module loader
  • ❌ Modify runtime globals
  • ❌ Optimize for browsers or Node

If you want a bundler, use a bundler.

This tool exists specifically for environments where bundlers do not work.


Design principles

  1. Runtime minimalism The output must be as simple as possible.

  2. Build-time maximalism Complexity is allowed—encouraged—at build time.

  3. Deterministic output The same input always produces the same script.

  4. Explicit over clever No magic globals, no hidden runtime behavior.

  5. Hostile runtime first If it works in a broken engine, it will work anywhere.


Intended workflow

src/
 ├─ rules.ts
 ├─ utils.ts
 └─ main.ts   ← entry

        ↓

ts-cmacro src/main.ts -o dist/script.ts

        ↓

dist/script.ts   ← flat, top-level TypeScript

        ↓

tsc dist/script.ts --outFile dist/script.js

        ↓

dist/script.js   ← flat, top-level JavaScript

You keep full IDE support:

  • Type checking
  • Go-to-definition
  • Refactoring
  • Code navigation

The runtime gets none of the complexity.


Status

🚧 Early design / MVP stage

The initial version focuses on:

  • Single entry point
  • Relative imports
  • Import/export stripping
  • Ordered concatenation

Future features are explicitly out of scope until the core is proven stable.


Who this is for

You may want this tool if:

  • You write JS for constrained or embedded environments
  • You maintain large configuration scripts
  • You are tired of "just copy-paste everything into one file"
  • You want TypeScript ergonomics without runtime cost

If your runtime supports modern ESM—you probably don’t need this.


Philosophy summary

Use modern tools to generate primitive code.

That’s it.


License

GPLV3