Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
191c4ad
feat: implement full standard library lowerings and gcc toolchain dri…
mcpe500 Aug 28, 2026
f2412f7
Merge remote-tracking branch 'origin/main'
mcpe500 Aug 28, 2026
182d402
fix: preserve Array.isArray computed side effects and support Date in…
mcpe500 Aug 28, 2026
93c8c17
feat: implement core stdlib lowerings phase 1-2 (2701-2712)
mcpe500 Aug 28, 2026
8a63e80
feat: implement catch/inspect/join phase 3 lanjutan (2713-2715)
mcpe500 Aug 28, 2026
921d62c
feat: implement collections & type representations phase 4 (2716-2717)
mcpe500 Aug 28, 2026
a3c0220
feat: optional chain over primitive receivers corpus, already green a…
mcpe500 Aug 28, 2026
9b46a4c
feat: import.meta.url lowering to file:// module URI (2722)
mcpe500 Aug 28, 2026
d407013
feat: Promise.all heterogeneous/empty tuple lowerings (2723)
mcpe500 Aug 28, 2026
06eca1a
feat: boundary callback thunk for Error params crossing into dynamica…
mcpe500 Aug 28, 2026
82d12ab
feat: SC0004 panic guard for tuple/type-reference checker shapes (2726)
mcpe500 Aug 28, 2026
194ee01
fix: honor configured compiler for vendor archives
mcpe500 Aug 28, 2026
ca298b1
feat: lower spread over dynamic values (2724)
mcpe500 Aug 28, 2026
ff673d7
feat: cover any to socket casts (2725)
mcpe500 Aug 28, 2026
f8f363b
feat: support class interface width coercion (2719)
mcpe500 Aug 28, 2026
d1330f8
feat: cover intersection expando lowering (2720)
mcpe500 Aug 28, 2026
c79a042
fix: restrict checker panic fence to checker panics
mcpe500 Aug 28, 2026
569b945
fix: escape import.meta.url paths
mcpe500 Aug 28, 2026
88ecf7b
merge: phase 6 panic guard lane
mcpe500 Aug 28, 2026
8aa5003
merge: phase 5 boundary coercion lane
mcpe500 Aug 28, 2026
d0231cb
merge: phase 6 stretch lane
mcpe500 Aug 28, 2026
5dc065c
feat: add os.arch alias and Promise.allSettled lowering (2727-2728)
mcpe500 Aug 29, 2026
4b87896
fix: honor SCRIPTC_CC in mbedtls vendor builds; verbose island stacks…
mcpe500 Aug 29, 2026
2884e64
feat(runtime): ship precompiled macOS artifacts (#248)
ctate Aug 28, 2026
1c9dce1
update dockerfile (#264)
ctate Aug 30, 2026
325b7b0
fix(compiler): reshape inline record assertions (#266)
ctate Aug 30, 2026
d407978
optimize string self-concatenation ownership (#267)
ctate Aug 30, 2026
4d5631b
fix ffi call initializers (#268)
ctate Aug 31, 2026
c4c6f2b
fix(library): reject callback re-entry (#270)
ctate Aug 31, 2026
1ce187c
Tree-shake unreachable executable runtime sections (#271)
ctate Aug 31, 2026
834ac02
fix(compiler): keep targetless Zig native builds coherent (#273)
ctate Aug 31, 2026
47a8e95
Support reusePort for TCP and HTTP server listeners (#274)
ctate Aug 31, 2026
11add36
chore(release): v0.0.36 (#277)
ctate Aug 31, 2026
6179b4b
Add sparse UTF-16 indexing for large strings (#275)
ctate Aug 31, 2026
6a09c05
Separate native linking from C compilation (#278)
ctate Sep 1, 2026
7f52ad9
feat: implement core stdlib lowerings phase 1-2 (2701-2712)
mcpe500 Aug 28, 2026
80658a4
feat(t3): L1 frontend graph transitive
mcpe500 Aug 29, 2026
b87938d
feat(t3): L2 rewrite & lexer CJS/ESM broadened (per-file fallback, al…
mcpe500 Aug 29, 2026
fe68f74
feat(t3): L3 lowering per-file island fallback
mcpe500 Aug 29, 2026
40e7bbc
feat(t3): L4 backend moduleUses gating
mcpe500 Aug 29, 2026
7e54828
feat(t3): L5 runtime native builtins
mcpe500 Aug 29, 2026
c4356fc
feat(t3): L6 cli per-file npm-static auto
mcpe500 Aug 29, 2026
28603c2
fix(t3): unignore 2733 pg fixture dist (renamed to minified/)
mcpe500 Aug 29, 2026
74ebe93
fix(runtime): harden cross-platform shims
mcpe500 Sep 1, 2026
0f328c2
fix: preserve heterogeneous Promise.all promises
mcpe500 Sep 1, 2026
f2477e7
fix(llvm): preserve splice replacement items
mcpe500 Sep 1, 2026
10224ad
fix: propagate timingSafeEqual exceptions
mcpe500 Sep 1, 2026
a889470
fix: heterogeneous Promise.all tuple uses concurrent intrinsic
mcpe500 Sep 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ jobs:
- run: brew install llvm@22
- run: pnpm install --frozen-lockfile
- run: pnpm --filter @scriptc/llvm-darwin-arm64 build:native
- run: pnpm --filter @scriptc/runtime-darwin-arm64 build:native
- run: pnpm build
# Separate vitest invocations because the shard axes must not mix: a file
# lands in exactly ONE --shard slice, so an env-sharded file behind
Expand Down Expand Up @@ -135,6 +136,7 @@ jobs:
- run: brew install llvm@22
- run: pnpm install --frozen-lockfile
- run: pnpm --filter @scriptc/llvm-darwin-arm64 build:native
- run: pnpm --filter @scriptc/runtime-darwin-arm64 build:native
- run: pnpm build
- name: No-clang assembly/object contract
if: matrix.shard == 1
Expand All @@ -144,8 +146,17 @@ jobs:
run: >-
pnpm test
packages/compiler/test/native-codegen-integration.test.ts
packages/compiler/src/backend/runtime-pack.test.ts
packages/cli/test/native-link-info.test.ts
packages/cli/test/runtime-pack.test.ts
tests/harness/native-object-example.test.ts
- name: Default helper/runtime-pack executable does not compile C
if: matrix.shard == 1
env:
SCRIPTC_LEGACY_C_PIPELINE: "0"
run: >-
pnpm test packages/cli/test/runtime-pack.test.ts
--testNamePattern "legacy C pipeline disabled"
- name: LLVM-tier helper object differential (${{ matrix.shard }}/3)
env:
SCRIPTC_LLVM_HELPER_ONLY: "1"
Expand All @@ -160,11 +171,13 @@ jobs:
if: matrix.shard == 1
run: |
pnpm --dir packages/runtime pack --pack-destination "$RUNNER_TEMP" --silent
pnpm --dir packages/runtime-darwin-arm64 pack --pack-destination "$RUNNER_TEMP" --silent
pnpm --dir packages/compiler pack --pack-destination "$RUNNER_TEMP" --silent
pnpm --dir packages/cli pack --pack-destination "$RUNNER_TEMP" --silent
PREFIX="$RUNNER_TEMP/installed-scriptc"
npm install --prefix "$PREFIX" --ignore-scripts \
"$RUNNER_TEMP/scriptc-runtime-$(node -p "require('./packages/runtime/package.json').version").tgz" \
"$RUNNER_TEMP/scriptc-runtime-darwin-arm64-$(node -p "require('./packages/runtime-darwin-arm64/package.json').version").tgz" \
"$RUNNER_TEMP/scriptc-llvm-darwin-arm64-$(node -p "require('./packages/llvm-darwin-arm64/package.json').version").tgz" \
"$RUNNER_TEMP/scriptc-compiler-$(node -p "require('./packages/compiler/package.json').version").tgz" \
"$RUNNER_TEMP/scriptc-$(node -p "require('./packages/cli/package.json').version").tgz"
Expand Down
10 changes: 6 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ jobs:

# Publishing uses npm trusted publishing (OIDC): the job's id-token
# permission lets npm mint short-lived credentials, so no npm token
# secret exists anywhere in this repo. All four packages —
# @scriptc/runtime, @scriptc/llvm-darwin-arm64, @scriptc/compiler,
# and scriptc — must each be
# secret exists anywhere in this repo. All five packages —
# @scriptc/runtime, @scriptc/runtime-darwin-arm64,
# @scriptc/llvm-darwin-arm64, @scriptc/compiler, and scriptc — must each be
# configured on npmjs.com with a GitHub Actions trusted publisher
# pointing at repository vercel-labs/scriptc, workflow release.yml,
# environment Release. A package missing that configuration fails
Expand All @@ -92,12 +92,13 @@ jobs:
run: |
pnpm install --frozen-lockfile
pnpm --filter @scriptc/llvm-darwin-arm64 build:native
pnpm --filter @scriptc/runtime-darwin-arm64 build:native
pnpm -r build

- name: Check version sync
run: |
VERSION="${{ needs.check-release.outputs.version }}"
for pkg in packages/runtime packages/llvm-darwin-arm64 packages/compiler packages/cli; do
for pkg in packages/runtime packages/runtime-darwin-arm64 packages/llvm-darwin-arm64 packages/compiler packages/cli; do
V=$(node -p "require('./$pkg/package.json').version")
if [ "$V" != "$VERSION" ]; then
echo "Version mismatch: $pkg is $V, expected $VERSION"
Expand Down Expand Up @@ -149,6 +150,7 @@ jobs:
}

publish_dir packages/runtime
publish_dir packages/runtime-darwin-arm64
publish_dir packages/llvm-darwin-arm64 "$HELPER_TARBALL"
publish_dir packages/compiler
publish_dir packages/cli
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ node_modules/
!tests/fixtures/node-types/node_modules/
dist/
/packages/llvm-darwin-arm64/bin/
/packages/runtime-darwin-arm64/artifacts/
/packages/runtime-darwin-arm64/runtime-pack.json
/packages/runtime-darwin-arm64/.runtime-pack-*
!tests/fixtures/fetch/node_modules/eventsource-parser/dist/
!tests/fixtures/npm/node_modules/*/dist/
!tests/fixtures/npm/workspace/*/dist/
Expand Down
11 changes: 6 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ pnpm install && pnpm -r build # build the workspace
pnpm test:sandbox # full gate: ~4m custom image, ~9m cold managed fallback
```

The ordinary workspace build does not rebuild the packaged macOS LLVM helper.
When changing native assembly/object emission, install CMake, Ninja, and
Homebrew `llvm@22`, then run
`pnpm --filter @scriptc/llvm-darwin-arm64 build:native` explicitly. The macOS
full test suite also needs that generated helper.
The ordinary workspace build does not rebuild packaged macOS native artifacts.
When changing native assembly/object emission or runtime-pack selection,
install CMake, Ninja, and Homebrew `llvm@22`, then run
`pnpm --filter @scriptc/llvm-darwin-arm64 build:native` and
`pnpm --filter @scriptc/runtime-darwin-arm64 build:native` explicitly. The
macOS full test suite also needs those generated artifacts.

Use focused local tests while iterating, then use `pnpm test:sandbox` whenever a
full validation gate is required. It loads Sandbox configuration from the
Expand Down
13 changes: 10 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,20 @@ All notable changes to scriptc will be documented in this file.

## Unreleased

<!-- release:start -->

## 0.0.36

### Fixes

- **Library host-callback re-entry now traps deterministically.** Entering an export or library control/registration ABI symbol while a synchronous host callback is active delivers the structured `SC4026` diagnostic to the existing panic sink, attributes the attempted inner symbol, and poisons only that library instance.

### Features

- **macOS arm64 executables use release-built runtime packs.** LLVM-tier builds now emit the program object through the bundled helper and link feature-selected, hashed runtime/vendor artifacts without compiling C on the user's machine. Explicit C, LLVM fallback, and sanitizer builds retain the external C-toolchain path.
- **Builds can stop at typed IR, readable C, or textual LLVM IR.** `scriptc build --emit=ir|c|llvm` writes one primary source artifact with stable default suffixes and requires only Node—no external compiler, archiver, linker, or executable cache. `--emit=exe` remains the default, and executable builds retain the former additive `--emit-ir` flag for one release with a deprecation warning; library mode keeps its additive `--emit-ir` option.

<!-- release:start -->
<!-- release:end -->

## 0.0.35

Expand All @@ -22,8 +31,6 @@ All notable changes to scriptc will be documented in this file.
- **Unsupported `Array.from` element shapes refuse cleanly.** Mapper results that the backends cannot represent are diagnosed or deferred before emission instead of reaching a C emitter crash.
- **JSDoc record equality reads preserve dynamic property behavior.** Dot and bracket reads used by strict-equality and missing-key probes now route through checked-dynamic lookup, preserving absent properties and object identity.

<!-- release:end -->

## 0.0.34

### Performance
Expand Down
1 change: 1 addition & 0 deletions Dockerfile.sandbox
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ WORKDIR /workspace
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
COPY packages/cli/package.json packages/cli/package.json
COPY packages/cli/scripts/warm-cache.mjs packages/cli/scripts/warm-cache.mjs
COPY packages/cli/scripts/runtime-pack-host.mjs packages/cli/scripts/runtime-pack-host.mjs
COPY packages/compiler/package.json packages/compiler/package.json
COPY packages/runtime/package.json packages/runtime/package.json

Expand Down
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# scriptc

scriptc compiles TypeScript and JavaScript to typed IR, readable C, textual LLVM IR, native assembly and objects, native executables, and WebAssembly modules. It uses the TypeScript compiler for parsing and type checking. Source outputs require only Node; macOS 15+ arm64 assembly/object output uses scriptc's bundled LLVM helper; executable builds currently use clang to compile/link the runtime.
scriptc compiles TypeScript and JavaScript to typed IR, readable C, textual LLVM IR, native assembly and objects, native executables, and WebAssembly modules. It uses the TypeScript compiler for parsing and type checking. Source outputs require only Node. On macOS 15+ arm64, ordinary LLVM-tier executables use scriptc's bundled helper and precompiled runtime pack; clang is only the platform linker driver and does not compile program or runtime C.

Static builds include a small native runtime, but no Node or JavaScript engine. Code that cannot compile statically is reported as a diagnostic. For npm packages and `any`-typed code, `--dynamic` embeds [quickjs-ng](https://github.com/quickjs-ng/quickjs) explicitly.

scriptc is experimental and targets macOS, Linux, Windows, and WebAssembly via WASI Preview 1.

## Installation

The compiler requires Node.js 24 or newer. `--emit=ir|c|llvm` needs only Node. On macOS 15+ arm64, `--emit=asm|obj` additionally uses the optional platform helper installed with scriptc, but needs no compiler, archiver, linker, or SDK. Executable builds still require clang and the platform SDK. The executables it produces do not require Node.
The compiler requires Node.js 24 or newer. `--emit=ir|c|llvm` needs only Node. On macOS 15+ arm64, `--emit=asm|obj` additionally uses the optional platform helper installed with scriptc, but needs no compiler, archiver, linker, or SDK. Ordinary LLVM-tier executable builds need a platform linker driver and SDK, but use the bundled helper plus precompiled runtime pack rather than compiling generated or runtime C. Set `SCRIPTC_LINKER` to choose that driver. Explicit C builds, LLVM fallbacks, `--sanitize`, and the deprecated `SCRIPTC_CC=clang|zigcc` compatibility route additionally need a C compiler. The executables it produces do not require Node.

```console
$ npm install -g scriptc
Expand Down Expand Up @@ -154,10 +154,11 @@ $ pnpm test:sandbox
```

The normal workspace build needs no local LLVM installation. To rebuild the
optional macOS arm64 assembly/object helper, install CMake, Ninja, and
Homebrew `llvm@22`, then run
`pnpm --filter @scriptc/llvm-darwin-arm64 build:native`. The macOS full test
suite also uses that generated helper.
optional macOS arm64 native artifacts, install CMake, Ninja, and Homebrew
`llvm@22`, then run
`pnpm --filter @scriptc/llvm-darwin-arm64 build:native` and
`pnpm --filter @scriptc/runtime-darwin-arm64 build:native`. The macOS full test
suite also uses those generated artifacts.

`pnpm test:sandbox` loads `.env.local`, preflights Vercel authentication and
project access, and uses the managed `vercel/sandbox/universal` image by
Expand Down
22 changes: 12 additions & 10 deletions RELEASING.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
# Releasing

Releases are manual, single-commit affairs. The maintainer controls the changelog voice and format. The four npm packages — `@scriptc/runtime`, `@scriptc/llvm-darwin-arm64`, `@scriptc/compiler`, and `scriptc` — always publish together at the same version.
Releases are manual, single-commit affairs. The maintainer controls the changelog voice and format. The five npm packages — `@scriptc/runtime`, `@scriptc/runtime-darwin-arm64`, `@scriptc/llvm-darwin-arm64`, `@scriptc/compiler`, and `scriptc` — always publish together at the same version.

To prepare a release:

1. Bump the version in `packages/cli/package.json`
2. Run `node scripts/sync-versions.mjs` to stamp the same version into `packages/runtime`, `packages/llvm-darwin-arm64`, and `packages/compiler`, then `pnpm manifest` to restamp `packages/compiler/surface-manifest.json` with the new version, and commit both (the test suite's staleness guard fails on a version drift)
2. Run `node scripts/sync-versions.mjs` to stamp the same version into `packages/runtime`, `packages/runtime-darwin-arm64`, `packages/llvm-darwin-arm64`, and `packages/compiler`, then `pnpm manifest` to restamp `packages/compiler/surface-manifest.json` with the new version, and commit both (the test suite's staleness guard fails on a version drift)
3. Fold the `## Unreleased` section of `CHANGELOG.md` into a new `## <version>` entry (newest first, below `## Unreleased`), and leave `## Unreleased` empty for the next cycle
4. Wrap the new entry in `<!-- release:start -->` and `<!-- release:end -->` markers; this marked block is also the GitHub release body
5. Remove the `<!-- release:start -->` and `<!-- release:end -->` markers from the previous release entry; only the latest release should have markers
6. With Zig on `PATH`, run `SCRIPTC_CROSS=1 pnpm exec vitest run tests/harness/library-cross.test.ts` and require the cross-target library conformance lane to pass
7. Commit to `main`

CI (`.github/workflows/release.yml`) compares the version in `packages/cli/package.json` to what `scriptc` has on npm. If it differs, it builds the workspace, verifies all four package versions match (a mismatch fails with a hint to run `scripts/sync-versions.mjs`), and publishes to npm in dependency order — `@scriptc/runtime`, `@scriptc/llvm-darwin-arm64`, `@scriptc/compiler`, then `scriptc` — so each package's dependencies are resolvable the moment it lands. After the publish succeeds, a separate job creates the git tag `v<version>` and the GitHub release with the marked changelog entry as its body, and attaches `surface-manifest.json` — the machine-readable listing of the surface the static tier compiles at that version (stable per-entry ids, so two releases diff mechanically; see `packages/compiler/src/coverage/surface-manifest.ts` for the schema). The job regenerates the manifest from the tree and fails on any byte difference from the committed file before attaching, so the asset is always the manifest of the code being released. The same file ships inside the `@scriptc/compiler` package as `@scriptc/compiler/surface-manifest.json`.
CI (`.github/workflows/release.yml`) compares the version in `packages/cli/package.json` to what `scriptc` has on npm. If it differs, it builds the workspace, verifies all five package versions match (a mismatch fails with a hint to run `scripts/sync-versions.mjs`), and publishes to npm in dependency order — `@scriptc/runtime`, `@scriptc/runtime-darwin-arm64`, `@scriptc/llvm-darwin-arm64`, `@scriptc/compiler`, then `scriptc` — so each package's dependencies are resolvable the moment it lands. After the publish succeeds, a separate job creates the git tag `v<version>` and the GitHub release with the marked changelog entry as its body, and attaches `surface-manifest.json` — the machine-readable listing of the surface the static tier compiles at that version (stable per-entry ids, so two releases diff mechanically; see `packages/compiler/src/coverage/surface-manifest.ts` for the schema). The job regenerates the manifest from the tree and fails on any byte difference from the committed file before attaching, so the asset is always the manifest of the code being released. The same file ships inside the `@scriptc/compiler` package as `@scriptc/compiler/surface-manifest.json`.

The release job runs on macOS arm64, builds and strips the pinned LLVM helper,
and publishes its constrained platform package before `@scriptc/compiler`.
Executable/runtime compilation still uses the user's local clang; the helper
owns only assembly/object code generation. The npm package's best-effort
postinstall warms runtime, TLS, and engine caches against that exact local
toolchain. The GitHub release remains a tag, release notes, and the manifest
asset; the npm publish never waits on the GitHub release.
then builds the matching precompiled runtime pack before publishing both
constrained platform packages ahead of `@scriptc/compiler`. Ordinary LLVM-tier
executables use the helper for the program object and the platform pack for
runtime objects; the user's toolchain performs only the final platform link.
Explicit C builds, LLVM refusals, and `--sanitize` retain the external C
toolchain path. npm postinstall skips local runtime-cache compilation when the
platform pack is available. The GitHub release remains a tag, release notes, and the
manifest asset; the npm publish never waits on the GitHub release.

Publishing uses npm trusted publishing (OIDC) — there is no npm token secret.
Each of the four packages must have a GitHub Actions trusted publisher for
Each of the five packages must have a GitHub Actions trusted publisher for
`release.yml` and the `Release` environment. A missing configuration fails
before upload. Re-runs skip package versions already present on npm, so a
partially published release can be resumed safely.
Loading