rbxts-transform-boost 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  >
5
5
  > **What carried over:** Luau type annotation injection on function parameters for native codegen (primitives, Roblox value types, arrays).
6
6
  >
7
- > **What's new:** `--!optimize 2` on every file, `game:GetService()` hoisting to module-level locals, repeated property chain hoisting, loop bounds hoisting, `const` keyword for TypeScript `const` declarations, output formatting so compiled files look human-written.
7
+ > **What's new:** `--!optimize 2` on every file, `game:GetService()` hoisting to module-level locals, repeated property chain hoisting, `const` keyword for TypeScript `const` declarations, output formatting so compiled files look human-written.
8
8
  >
9
9
  > **What's different:** The old package also annotated return types, local variable declarations, class methods, and user-defined interfaces/type aliases. Those are not yet in this package — they're planned. The old package also had reliability issues that this rewrite addresses.
10
10
 
@@ -204,68 +204,6 @@ end
204
204
 
205
205
  ---
206
206
 
207
- ### Loop bounds hoisting
208
-
209
- `arr.size()` in a `for` loop condition is re-evaluated on every iteration in compiled output. The loops pass hoists it to a local before the loop.
210
-
211
- ```typescript
212
- // TypeScript source
213
- export function sumWeighted(values: Array<number>, weights: Array<number>): number {
214
- let total = 0;
215
- for (let i = 0; i < values.size(); i++) {
216
- total += values[i] * weights[i];
217
- }
218
- return total;
219
- }
220
- ```
221
-
222
- ```lua
223
- -- Without transformer
224
- local function sumWeighted(values, weights)
225
- local total = 0
226
- for i = 0, #values - 1 do
227
- total += values[i + 1] * weights[i + 1]
228
- end
229
- return total
230
- end
231
- ```
232
-
233
- ```lua
234
- -- With transformer
235
- local function sumWeighted(values: {number}, weights: {number}): number
236
- local total = 0
237
-
238
- do
239
- const _len_values = #values
240
-
241
- do
242
- local i = 0
243
- local _shouldIncrement = false
244
-
245
- while true do
246
- if _shouldIncrement then
247
- i += 1
248
- else
249
- _shouldIncrement = true
250
- end
251
-
252
- if not (i < _len_values) then
253
- break
254
- end
255
-
256
- total += values[i + 1] * weights[i + 1]
257
- end
258
- end
259
- end
260
-
261
- return total
262
- end
263
- ```
264
-
265
- **2.3× faster** (combined with `--!native` and type annotations on `values`/`weights`).
266
-
267
- ---
268
-
269
207
  ### Luau type annotation injection
270
208
 
271
209
  After the compiler writes `.luau` files, the transformer injects Luau type annotations on function parameters and return types. This lets the native compiler generate specialized code for numeric and Roblox value types.
@@ -342,33 +280,33 @@ local data = TS.import(script, ...)
342
280
 
343
281
  ## Benchmarks
344
282
 
345
- Measured in Roblox Studio server context. 100,000 iterations per benchmark (10,000 for `cfLookAt`). Same TypeScript source compiled two ways with and without the transformer.
283
+ Measured in Roblox Studio server context. 100,000 iterations per benchmark (10,000 for `cfLookAt`). Both suites use `//!native` the only variable is whether the transformer is applied, so the numbers reflect what the transformer itself contributes on top of native.
346
284
 
347
285
  | Benchmark | With transformer | Without | Speedup | Driver |
348
286
  |-----------|-----------------|---------|---------|--------|
349
- | integrate (Verlet) | 0.042 µs | 0.055 µs | **1.3×** | `--!native` + type annotations |
350
- | dot (V3 manual) | 0.016 µs | 0.032 µs | **2.0×** | `--!native` |
351
- | cross (V3 manual) | 0.018 µs | 0.049 µs | **2.7×** | `--!native` + 6× field hoisting |
352
- | lerpVec3 (V3 manual) | 0.015 µs | 0.047 µs | **3.1×** | `--!native` + 3× field hoisting |
353
- | encodeFixed (buf+math) | 0.015 µs | 0.032 µs | **2.1×** | `--!native` |
354
- | encodePacket (3× fixed) | 0.018 µs | 0.067 µs | **3.7×** | `--!native` stacked across 3 calls |
355
- | sumWeighted (loop) | 0.046 µs | 0.107 µs | **2.3×** | `--!native` + loop bounds hoist |
356
- | dotProduct (loop) | 0.067 µs | 0.109 µs | **1.6×** | `--!native` + loop bounds hoist |
357
- | norm (loop+sqrt) | 0.048 µs | 0.111 µs | **2.3×** | `--!native` + loop bounds hoist |
358
- | mathHeavy (trig+sqrt) | 0.038 µs | 0.052 µs | **1.4×** | `--!native` |
359
- | fib(20) (iter) | 0.048 µs | 0.155 µs | **3.2×** | `--!native` on integer loop |
360
- | cfLookAt (ctor) | 0.079 µs | 0.079 µs | 1.0× | C++ floor — no Luau work |
361
- | cfChain (mul+angles) | 0.076 µs | 0.077 µs | 1.0× | C++ floor — no Luau work |
362
- | serviceWork (GetService ×2) | 0.185 µs | 0.440 µs | **2.4×** | GetService hoisting |
363
- | multiSvc (GetService ×3) | 0.142 µs | 0.480 µs | **3.4×** | GetService hoisting |
364
- | cameraWork (prop chain) | 0.148 µs | 0.215 µs | **1.5×** | `camera.CFrame` hoisted (2 reads → 1) |
365
- | formatStats (template) | 0.170 µs | 0.175 µs | ~1× | String — no arithmetic |
366
- | buildKey (template) | 0.068 µs | 0.086 µs | **1.3×** | `--!native` |
287
+ | integrate (Verlet) | 0.058 µs | 0.071 µs | **1.2×** | type annotations |
288
+ | dot (V3 manual) | 0.025 µs | 0.046 µs | **1.8×** | type annotations |
289
+ | cross (V3 manual) | 0.024 µs | 0.072 µs | **3.0×** | 6× field hoisting + type annotations |
290
+ | lerpVec3 (V3 manual) | 0.026 µs | 0.061 µs | **2.3×** | 3× field hoisting + type annotations |
291
+ | encodeFixed (buf+math) | 0.025 µs | 0.026 µs | ~1× | |
292
+ | encodePacket (3× fixed) | 0.030 µs | 0.028 µs | ~1× | |
293
+ | sumWeighted (loop) | 0.051 µs | 0.054 µs | ~1× | type annotations |
294
+ | dotProduct (loop) | 0.050 µs | 0.060 µs | **1.2×** | type annotations |
295
+ | norm (loop+sqrt) | 0.052 µs | 0.058 µs | **1.1×** | type annotations |
296
+ | mathHeavy (trig+sqrt) | 0.044 µs | 0.050 µs | **1.1×** | type annotations |
297
+ | fib(20) (iter) | 0.062 µs | 0.071 µs | **1.1×** | type annotations |
298
+ | cfLookAt (ctor) | 0.087 µs | 0.082 µs | ~1× | C++ floor — no Luau work |
299
+ | cfChain (mul+angles) | 0.102 µs | 0.092 µs | ~1× | C++ floor — no Luau work |
300
+ | serviceWork (GetService ×2) | 0.243 µs | 0.481 µs | **2.0×** | GetService hoisting |
301
+ | multiSvc (GetService ×3) | 0.154 µs | 0.505 µs | **3.3×** | GetService hoisting |
302
+ | cameraWork (prop chain) | 0.185 µs | 0.218 µs | **1.2×** | `camera.CFrame` hoisted (2 reads → 1) |
303
+ | formatStats (template) | 0.191 µs | 0.187 µs | ~1× | string — no arithmetic |
304
+ | buildKey (template) | 0.085 µs | 0.079 µs | ~1× | |
367
305
 
368
306
  ### What the transformer cannot help with
369
307
 
370
- - **Pure engine API calls** — `CFrame.lookAt`, `CFrame.Angles`, `CFrame` multiplication all execute immediately in C++. `--!native` cannot speed up code that is already running natively. `cfLookAt` and `cfChain` show 1.0× for this reason.
371
- - **Single-access properties** — the cache pass only hoists when a property is read 2+ times in the same function. One read has nothing to eliminate.
308
+ - **Pure engine API calls** — `CFrame.lookAt`, `CFrame.Angles`, `CFrame` multiplication execute immediately in C++. `--!native` cannot speed up code that is already running natively.
309
+ - **Single-access properties** — the cache pass only hoists when a property is read 2+ times in the same function.
372
310
  - **String-heavy functions** — Luau string operations are not meaningfully accelerated by the native compiler.
373
311
 
374
312
  ---
package/dist/index.js CHANGED
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = default_1;
4
4
  const native_1 = require("./passes/native");
5
5
  const cache_1 = require("./passes/cache");
6
- const loops_1 = require("./passes/loops");
7
6
  const annotate_1 = require("./passes/annotate");
8
7
  function default_1(program, config = {}, { ts }) {
9
8
  const { optimize = true, strict = true, hoist = true } = config;
@@ -12,7 +11,6 @@ function default_1(program, config = {}, { ts }) {
12
11
  let result = sourceFile;
13
12
  if (hoist)
14
13
  result = (0, cache_1.cachePass)(ts, program, ctx, result);
15
- result = (0, loops_1.loopsPass)(ts, program, ctx, result);
16
14
  if (optimize || strict)
17
15
  result = (0, native_1.nativePass)(ts, ctx, result, optimize, strict);
18
16
  return result;
@@ -249,10 +249,10 @@ function organizePreamble(src) {
249
249
  const out = [...shebang];
250
250
  if (header.length > 0)
251
251
  out.push("", ...header);
252
- if (runtime.length > 0)
253
- out.push("", "-- Runtime", ...runtime);
254
252
  if (services.length > 0)
255
253
  out.push("", "-- Services", ...services);
254
+ if (runtime.length > 0)
255
+ out.push("", "-- Runtime", ...runtime);
256
256
  for (const group of importGroups) {
257
257
  group.lines.sort(byLengthDesc);
258
258
  out.push("", group.label, ...group.lines);
package/package.json CHANGED
@@ -1,14 +1,18 @@
1
1
  {
2
2
  "name": "rbxts-transform-boost",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "roblox-ts transformer: automatic --!native, GetService hoisting, property chain caching, loop bounds hoisting, and Luau type annotation injection",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist",
9
+ "README.md"
10
+ ],
7
11
  "scripts": {
8
12
  "build": "tsc",
9
13
  "bench:build": "npm run build && cd bench && ~/.rokit/bin/rotor build",
10
14
  "bench:build:baseline": "cd bench && ~/.rokit/bin/rotor build -p tsconfig.notransform.json -i out/include",
11
- "bench:rbxlx": "npm run bench:build && npm run bench:build:baseline && cd bench && ~/.rokit/bin/rojo build benchmark.project.json -o benchmark.rbxlx"
15
+ "bench:rbxlx": "npm run bench:build && npm run bench:build:baseline && cd bench && ~/.rokit/bin/rojo build default.project.json -o benchmark.rbxlx"
12
16
  },
13
17
  "keywords": [
14
18
  "roblox-ts",
@@ -22,6 +26,7 @@
22
26
  "typescript": ">=5.0.0"
23
27
  },
24
28
  "devDependencies": {
25
- "@types/node": "^26.0.0"
29
+ "@types/node": "^26.0.0",
30
+ "typescript": "^5.9.3"
26
31
  }
27
32
  }
@@ -1,26 +0,0 @@
1
- name: Publish to npm
2
-
3
- on:
4
- push:
5
- tags:
6
- - "v*"
7
- workflow_dispatch:
8
-
9
- jobs:
10
- publish:
11
- runs-on: ubuntu-latest
12
- steps:
13
- - uses: actions/checkout@v4
14
-
15
- - uses: actions/setup-node@v4
16
- with:
17
- node-version: 20
18
- registry-url: https://registry.npmjs.org
19
-
20
- - run: npm ci
21
-
22
- - run: npm run build
23
-
24
- - run: npm publish --access public
25
- env:
26
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -1,20 +0,0 @@
1
- {
2
- "name": "perf-benchmark",
3
- "emitLegacyScripts": false,
4
- "tree": {
5
- "$className": "DataModel",
6
- "ServerScriptService": {
7
- "$className": "ServerScriptService",
8
- "$path": "out/src/server"
9
- },
10
- "ReplicatedStorage": {
11
- "$className": "ReplicatedStorage",
12
- "shared": {
13
- "$path": "out/src/shared"
14
- },
15
- "include": {
16
- "$path": "out/include"
17
- }
18
- }
19
- }
20
- }