tjs-lang 0.6.44 → 0.7.3

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.
Files changed (86) hide show
  1. package/CLAUDE.md +85 -422
  2. package/README.md +15 -82
  3. package/bin/benchmarks.ts +7 -7
  4. package/bin/dev.ts +2 -1
  5. package/demo/autocomplete.test.ts +1 -1
  6. package/demo/docs.json +744 -48
  7. package/demo/src/demo-nav.ts +5 -5
  8. package/demo/src/index.ts +28 -36
  9. package/demo/src/module-sw.ts +1 -1
  10. package/demo/src/playground-shared.ts +17 -17
  11. package/demo/src/playground.ts +13 -1
  12. package/demo/src/style.ts +4 -1
  13. package/demo/src/tjs-playground.ts +5 -5
  14. package/demo/src/user-store.ts +2 -1
  15. package/demo/static/favicon.svg +17 -24
  16. package/demo/static/tosi-platform.json +9304 -0
  17. package/dist/index.js +158 -156
  18. package/dist/index.js.map +14 -13
  19. package/dist/scripts/compat-effect.d.ts +16 -0
  20. package/dist/scripts/compat-kysely.d.ts +13 -0
  21. package/dist/scripts/compat-radash.d.ts +13 -0
  22. package/dist/scripts/compat-superstruct.d.ts +13 -0
  23. package/dist/scripts/compat-ts-pattern.d.ts +13 -0
  24. package/dist/scripts/compat-zod.d.ts +12 -0
  25. package/dist/src/lang/emitters/from-ts.d.ts +1 -1
  26. package/dist/src/lang/emitters/js-tests.d.ts +4 -0
  27. package/dist/src/lang/emitters/js.d.ts +2 -2
  28. package/dist/src/lang/index.d.ts +1 -0
  29. package/dist/src/lang/json-schema.d.ts +40 -0
  30. package/dist/src/lang/parser-transforms.d.ts +14 -0
  31. package/dist/src/lang/runtime.d.ts +39 -6
  32. package/dist/src/types/Type.d.ts +5 -0
  33. package/dist/tjs-full.js +158 -156
  34. package/dist/tjs-full.js.map +14 -13
  35. package/dist/tjs-vm.js +44 -43
  36. package/dist/tjs-vm.js.map +5 -5
  37. package/docs/README.md +21 -20
  38. package/docs/WASM-QUICKSTART.md +283 -0
  39. package/docs/diagrams/architecture-shift.svg +117 -0
  40. package/docs/diagrams/compile-runtime.svg +130 -0
  41. package/docs/diagrams/icon-riff-1.svg +55 -0
  42. package/docs/diagrams/icon-riff-2.svg +62 -0
  43. package/docs/diagrams/icon-riff-3.svg +61 -0
  44. package/docs/diagrams/platform-overview.svg +114 -0
  45. package/docs/diagrams/safe-eval.svg +147 -0
  46. package/docs/eval-v4/arch-comparison.svg +277 -0
  47. package/docs/eval-v4/bundler-tree.svg +250 -0
  48. package/docs/eval-v4/http-lifecycle.svg +148 -0
  49. package/docs/function-predicate-design.md +8 -8
  50. package/docs/native-engine-integration.md +2 -2
  51. package/editors/codemirror/autocomplete.test.ts +29 -29
  52. package/package.json +10 -4
  53. package/src/cli/commands/convert.test.ts +11 -8
  54. package/src/cli/tjs.ts +1 -1
  55. package/src/lang/codegen.test.ts +117 -112
  56. package/src/lang/docs.test.ts +22 -22
  57. package/src/lang/docs.ts +5 -8
  58. package/src/lang/emitters/dts.test.ts +13 -13
  59. package/src/lang/emitters/from-ts.ts +36 -9
  60. package/src/lang/emitters/js-tests.ts +143 -28
  61. package/src/lang/emitters/js.ts +49 -28
  62. package/src/lang/features.test.ts +259 -43
  63. package/src/lang/from-ts.test.ts +3 -3
  64. package/src/lang/function-predicate.test.ts +1 -1
  65. package/src/lang/index.ts +8 -47
  66. package/src/lang/json-schema.test.ts +261 -0
  67. package/src/lang/json-schema.ts +167 -0
  68. package/src/lang/parser-params.ts +28 -44
  69. package/src/lang/parser-transforms.ts +255 -0
  70. package/src/lang/parser.test.ts +32 -13
  71. package/src/lang/parser.ts +49 -11
  72. package/src/lang/perf.test.ts +11 -11
  73. package/src/lang/roundtrip.test.ts +3 -3
  74. package/src/lang/runtime.test.ts +167 -0
  75. package/src/lang/runtime.ts +234 -46
  76. package/src/lang/transpiler.test.ts +21 -21
  77. package/src/lang/typescript-syntax.test.ts +11 -9
  78. package/src/types/Type.ts +38 -1
  79. package/src/use-cases/bootstrap.test.ts +7 -7
  80. package/src/use-cases/client-server.test.ts +1 -1
  81. package/src/use-cases/malicious-actor.test.ts +1 -1
  82. package/src/use-cases/rag-processor.test.ts +1 -1
  83. package/src/use-cases/sophisticated-agents.test.ts +2 -2
  84. package/src/use-cases/transpiler-llm.test.ts +1 -1
  85. package/src/use-cases/unbundled-imports.test.ts +9 -9
  86. package/tjs-lang.svg +17 -25
package/CLAUDE.md CHANGED
@@ -52,6 +52,14 @@ bun run docs # Generate documentation
52
52
  # Build standalone CLI binaries
53
53
  bun run build:cli # Compiles tjs + tjsx to dist/
54
54
 
55
+ # Compatibility testing (transpile popular TS libraries with fromTS)
56
+ bun scripts/compat-zod.ts # Zod validation library
57
+ bun scripts/compat-effect.ts # Effect (HKTs, intersections)
58
+ bun scripts/compat-radash.ts # Radash utilities
59
+ bun scripts/compat-superstruct.ts # Superstruct validation
60
+ bun scripts/compat-ts-pattern.ts # ts-pattern matching
61
+ bun scripts/compat-kysely.ts # Kysely SQL builder
62
+
55
63
  # Deployment (Firebase)
56
64
  bun run deploy # Build demo + deploy functions + hosting
57
65
  bun run deploy:hosting # Hosting only (serves from .demo/)
@@ -80,6 +88,7 @@ bun run functions:serve # Local functions emulator
80
88
  - `src/lang/emitters/from-ts.ts` - TypeScript to TJS/JS transpiler with class metadata extraction
81
89
  - `src/lang/emitters/dts.ts` - .d.ts declaration file generator from TJS transpilation results
82
90
  - `src/lang/inference.ts` - Type inference from example values
91
+ - `src/lang/json-schema.ts` - JSON Schema generation from TypeDescriptors and example values
83
92
  - `src/lang/linter.ts` - Static analysis (unused vars, unreachable code, no-explicit-new)
84
93
  - `src/lang/runtime.ts` - TJS runtime (monadic errors, type checking, wrapClass)
85
94
  - `src/lang/wasm.ts` - WASM compiler (opcodes, disassembler, bytecode generation)
@@ -110,6 +119,16 @@ await vm.run(ast, args, { fuel, capabilities, timeoutMs, trace })
110
119
  // Builder
111
120
  Agent.take(schema).varSet(...).httpFetch(...).return(schema)
112
121
  vm.Agent // Builder with custom atoms included
122
+
123
+ // JSON Schema
124
+ Type('user', { name: '', age: 0 }).toJSONSchema() // → JSON Schema object
125
+ Type('user', { name: '', age: 0 }).strip(value) // → strip extra fields
126
+ functionMetaToJSONSchema(fn.__tjs) // → { input, output } schemas
127
+
128
+ // Error History (on by default, zero cost on happy path)
129
+ __tjs.errors() // → recent MonadicErrors (ring buffer, max 64)
130
+ __tjs.clearErrors() // → returns and clears
131
+ __tjs.getErrorCount() // → total since last clear
113
132
  ```
114
133
 
115
134
  ### Package Entry Points
@@ -128,7 +147,7 @@ TJS supports transpiling TypeScript to JavaScript with runtime type validation.
128
147
  **Step 1: TypeScript → TJS** (`fromTS`)
129
148
 
130
149
  ```typescript
131
- import { fromTS } from 'tosijs/lang/from-ts'
150
+ import { fromTS } from 'tjs-lang/lang/from-ts'
132
151
 
133
152
  const tsSource = `
134
153
  function greet(name: string): string {
@@ -138,7 +157,7 @@ function greet(name: string): string {
138
157
 
139
158
  const result = fromTS(tsSource, { emitTJS: true })
140
159
  // result.code contains TJS:
141
- // function greet(name: '') -> '' {
160
+ // function greet(name: ''): '' {
142
161
  // return \`Hello, \${name}!\`
143
162
  // }
144
163
  ```
@@ -146,10 +165,10 @@ const result = fromTS(tsSource, { emitTJS: true })
146
165
  **Step 2: TJS → JavaScript** (`tjs`)
147
166
 
148
167
  ```typescript
149
- import { tjs } from 'tosijs/lang'
168
+ import { tjs } from 'tjs-lang/lang'
150
169
 
151
170
  const tjsSource = `
152
- function greet(name: '') -> '' {
171
+ function greet(name: ''): '' {
153
172
  return \`Hello, \${name}!\`
154
173
  }
155
174
  `
@@ -161,8 +180,8 @@ const jsResult = tjs(tjsSource)
161
180
  **Full Chain Example:**
162
181
 
163
182
  ```typescript
164
- import { fromTS } from 'tosijs/lang/from-ts'
165
- import { tjs } from 'tosijs/lang'
183
+ import { fromTS } from 'tjs-lang/lang/from-ts'
184
+ import { tjs } from 'tjs-lang/lang'
166
185
 
167
186
  // TypeScript source with type annotations
168
187
  const tsSource = `
@@ -271,421 +290,53 @@ The `resolveValue()` function handles multiple input patterns:
271
290
 
272
291
  When `ctx.error` is set, subsequent atoms in a `seq` skip execution. Errors are wrapped in `AgentError`, not thrown. This prevents exception-based exploits.
273
292
 
274
- ### TJS Parser Syntax Extensions
275
-
276
- TJS extends JavaScript with type annotations that survive to runtime.
277
-
278
- #### Classes (Callable Without `new`)
279
-
280
- TJS classes are wrapped to be callable without the `new` keyword:
281
-
282
- ```typescript
283
- class Point {
284
- constructor(public x: number, public y: number) {}
285
- }
286
-
287
- // Both work identically:
288
- const p1 = Point(10, 20) // TJS way - clean
289
- const p2 = new Point(10, 20) // Still works, but linter warns
290
-
291
- // The linter flags explicit `new` usage:
292
- // Warning: Unnecessary 'new' keyword. In TJS, classes are callable without 'new'
293
- ```
294
-
295
- The `wrapClass()` function in the runtime uses a Proxy to intercept calls and auto-construct. Only `class` declarations in `.tjs` files with `TjsClass` are wrapped — built-in constructors (`Boolean`, `Number`, `String`, etc.) and old-style `function` + `prototype` constructors are never touched because they may have intentional dual behavior (e.g., `Boolean(0)` returns `false` but `new Boolean(0)` returns a truthy wrapper object).
296
-
297
- #### Function Parameters
298
-
299
- ```typescript
300
- // Required param with example value (colon shorthand)
301
- function greet(name: 'Alice') { } // name is required, type inferred as string
302
-
303
- // Numeric type narrowing (all valid JS syntax)
304
- function calc(rate: 3.14) { } // number (float) -- has decimal point
305
- function calc(count: 42) { } // integer -- whole number
306
- function calc(index: +0) { } // non-negative integer -- + prefix
307
-
308
- // Optional param with default
309
- function greet(name = 'Alice') { } // name is optional, defaults to 'Alice'
310
-
311
- // Object parameter with shape
312
- function createUser(user: { name: '', age: 0 }) { }
313
-
314
- // Nullable type
315
- function find(id: 0 | null) { } // integer or null
316
-
317
- // Optional TS-style
318
- function greet(name?: '') { } // same as name = ''
319
-
320
- // Rest parameters — array example is the type (annotation stripped in JS output)
321
- function sum(...nums: [0]) { } // nums: array of integers
322
- function log(...args: ['', 0, true]) { } // args: array<string | integer | boolean>
323
- ```
324
-
325
- #### Return Types
326
-
327
- ```typescript
328
- // Return type annotation (arrow syntax)
329
- function add(a: 0, b: 0) -> 0 { return a + b }
330
-
331
- // Object return type
332
- function getUser(id: 0) -> { name: '', age: 0 } { ... }
333
- ```
334
-
335
- #### Safety Markers
336
-
337
- ```typescript
338
- // Unsafe function (skips runtime validation)
339
- function fastAdd(! a: 0, b: 0) { return a + b }
340
-
341
- // Safe function (explicit validation)
342
- function safeAdd(? a: 0, b: 0) { return a + b }
343
-
344
- // Unsafe block
345
- unsafe {
346
- // All calls in here skip validation
347
- fastPath(data)
348
- }
349
- ```
350
-
351
- #### Type Declarations
352
-
353
- ```typescript
354
- // Simple type from example
355
- Type Name 'Alice'
356
-
357
- // Type with description and example
358
- Type User {
359
- description: 'a user object'
360
- example: { name: '', age: 0 }
361
- }
362
-
363
- // Type with predicate (auto-generates type guard from example)
364
- Type EvenNumber {
365
- description: 'an even number'
366
- example: 2
367
- predicate(x) { return x % 2 === 0 }
368
- }
369
- ```
370
-
371
- #### Generic Declarations
372
-
373
- ```typescript
374
- // Simple generic
375
- Generic Box<T> {
376
- description: 'a boxed value'
377
- predicate(x, T) {
378
- return typeof x === 'object' && x !== null && 'value' in x && T(x.value)
379
- }
380
- }
381
-
382
- // Generic with default type parameter
383
- Generic Container<T, U = ''> {
384
- description: 'container with label'
385
- predicate(obj, T, U) {
386
- return T(obj.item) && U(obj.label)
387
- }
388
- }
389
-
390
- // Generic with declaration block (for .d.ts emission)
391
- // The declaration block contains TypeScript syntax emitted verbatim into .d.ts
392
- // It is stripped from runtime JS output
393
- Generic BoxedProxy<T> {
394
- predicate(x, T) { return typeof x === 'object' && T(x.value) }
395
- declaration {
396
- value: T
397
- path: string
398
- observe(cb: (path: string) => void): void
399
- }
400
- }
401
- ```
402
-
403
- #### FunctionPredicate Declarations
404
-
405
- First-class function types, completing the Type/Generic/FunctionPredicate triad:
406
-
407
- ```typescript
408
- // Block form — declare a function type shape
409
- FunctionPredicate Callback {
410
- params: { x: 0, y: 0 }
411
- returns: ''
412
- }
413
-
414
- // Function form — extract signature from existing function
415
- FunctionPredicate Handler(existingFn, 'description')
416
-
417
- // Return contracts:
418
- // -> returns (standard)
419
- // -! assertReturns (throws on mismatch)
420
- // -? checkedReturns (wraps in MonadicError)
421
- ```
422
-
423
- Runtime creates a `RuntimeType` that checks `typeof === 'function'`. The spec includes params, returns, and returnContract. In `fromTS`, TS function type aliases (`type Cb = (x: number) => void`) emit FunctionPredicate declarations automatically.
424
-
425
- #### Bare Assignments
426
-
427
- ```typescript
428
- // Uppercase identifiers auto-get const
429
- Foo = Type('test', 'example') // becomes: const Foo = Type(...)
430
- MyConfig = { debug: true } // becomes: const MyConfig = { ... }
431
- ```
432
-
433
- #### Module Safety Directive
434
-
435
- ```typescript
436
- // At top of file - sets default validation level
437
- safety none // No validation (metadata only)
438
- safety inputs // Validate function inputs (default)
439
- safety all // Validate everything (debug mode)
440
- ```
441
-
442
- #### TJS Mode Directives
293
+ ### TJS Syntax Reference
443
294
 
444
- JavaScript semantics are the default. TJS improvements are opt-in via file-level directives:
295
+ Full syntax documentation is in [`CLAUDE-TJS-SYNTAX.md`](CLAUDE-TJS-SYNTAX.md). Key concepts:
445
296
 
446
- ```typescript
447
- TjsStrict // Enables ALL modes below at once
448
-
449
- TjsEquals // == and != use honest equality (Eq/NotEq) no coercion, unwraps boxed primitives
450
- TjsClass // Classes callable without new, explicit new is banned
451
- TjsDate // Date is banned, use Timestamp/LegalDate instead
452
- TjsNoeval // eval() and new Function() are banned
453
- TjsNoVar // var declarations are syntax errors — use const or let
454
- TjsStandard // Newlines as statement terminators (prevents ASI footguns)
455
- TjsSafeEval // Include Eval/SafeFunction in runtime for dynamic code
456
- ```
457
-
458
- Multiple directives can be combined. Place them at the top of the file before any code.
459
-
460
- #### Compile-Time Immutability (`const!`)
461
-
462
- `const!` declares bindings whose properties cannot be mutated. Enforced at transpile time with zero runtime cost — emits as plain `const`.
463
-
464
- ```typescript
465
- const! config = { debug: false, port: 8080 }
466
- console.log(config.port) // OK — reads are fine
467
- config.debug = true // ERROR at transpile time
468
-
469
- const! items = [1, 2, 3]
470
- items.map(x => x * 2) // OK — non-mutating methods
471
- items.push(4) // ERROR — mutating method
472
- ```
473
-
474
- Catches: property assignment, compound assignment (`+=`), increment/decrement, `delete`, and mutating array methods (`push`, `pop`, `splice`, `shift`, `unshift`, `sort`, `reverse`, `fill`).
475
-
476
- When runtimes support records/tuples, `const!` can emit those instead.
477
-
478
- #### Equality Operators
479
-
480
- With `TjsEquals` (or `TjsStrict`), TJS fixes JavaScript's confusing `==` coercion without the performance cost of deep structural comparison.
481
-
482
- | Operator | Meaning | Example |
483
- | ----------- | -------------------------------------------- | ---------------------------------- |
484
- | `==` | Honest equality (no coercion, unwraps boxed) | `new String('x') == 'x'` is `true` |
485
- | `!=` | Honest inequality | `0 != ''` is `true` (no coercion) |
486
- | `===` | Identity (same reference) | `obj === obj` is `true` |
487
- | `!==` | Not same reference | `{a:1} !== {a:1}` is `true` |
488
- | `a Is b` | Deep structural equality (explicit) | `{a:1} Is {a:1}` is `true` |
489
- | `a IsNot b` | Deep structural inequality (explicit) | `[1,2] IsNot [2,1]` is `true` |
490
-
491
- ```typescript
492
- // == is honest: no coercion, unwraps boxed primitives
493
- 'foo' == 'foo' // true
494
- new String('foo') == 'foo' // true (unwraps)
495
- new Boolean(false) == false // true (unwraps)
496
- null == undefined // true (nullish equality preserved)
497
- 0 == '' // false (no coercion!)
498
- false == [] // false (no coercion!)
499
-
500
- // == is fast: objects/arrays use reference equality (O(1))
501
- {a:1} == {a:1} // false (different refs)
502
- [1,2] == [1,2] // false (different refs)
503
-
504
- // Is/IsNot for explicit deep structural comparison (O(n))
505
- {a:1} Is {a:1} // true
506
- [1,2,3] Is [1,2,3] // true
507
- new Set([1,2]) Is new Set([2,1]) // true (Sets are order-independent)
508
- ```
509
-
510
- **Implementation Notes:**
511
-
512
- - **AJS (VM)**: The VM's expression evaluator (`src/vm/runtime.ts`) uses `isStructurallyEqual()` for `==`/`!=`
513
- - **TJS (browser/Node)**: Source transformation converts `==` to `Eq()` and `!=` to `NotEq()` calls
514
- - **`===` and `!==`**: Always preserved as identity checks, never transformed
515
- - `Eq()`/`NotEq()` — fast honest equality (unwraps boxed primitives, nullish equality, reference for objects)
516
- - `Is()`/`IsNot()` — deep structural comparison (arrays, objects, Sets, Maps, Dates, RegExps)
517
-
518
- **Custom Equality Protocol:**
519
-
520
- - `[tjsEquals]` symbol (`Symbol.for('tjs.equals')`) — highest priority, ideal for Proxies
521
- - `.Equals` method — backward-compatible, works on any object/class
522
- - Priority: symbol → `.Equals` → structural comparison
523
- - `tjsEquals` is exported from `src/lang/runtime.ts` and available as `__tjs.tjsEquals`
524
-
525
- #### Polymorphic Functions
526
-
527
- Multiple function declarations with the same name are merged into a dispatcher:
528
-
529
- ```typescript
530
- function area(radius: 3.14) {
531
- return Math.PI * radius * radius
532
- }
533
- function area(w: 0.0, h: 0.0) {
534
- return w * h
535
- }
536
-
537
- area(5) // dispatches to variant 1 (one number)
538
- area(3, 4) // dispatches to variant 2 (two numbers)
539
- ```
540
-
541
- Dispatch order: arity first, then type specificity, then declaration order. Ambiguous signatures (same types at same arity) are caught at transpile time.
542
-
543
- #### Polymorphic Constructors
544
-
545
- Classes can have multiple constructor signatures (requires `TjsClass` directive):
546
-
547
- ```typescript
548
- TjsClass
549
-
550
- class Point {
551
- constructor(x: 0.0, y: 0.0) {
552
- this.x = x
553
- this.y = y
554
- }
555
- constructor(coords: { x: 0.0; y: 0.0 }) {
556
- this.x = coords.x
557
- this.y = coords.y
558
- }
559
- }
297
+ - **Colon shorthand**: `function foo(x: 'hello')` — colon value is an _example_, not a type. This is the most common LLM mistake.
298
+ - **Numeric narrowing**: `3.14` = float, `42` = integer, `+0` = non-negative integer
299
+ - **Return types**: `function add(a: 0, b: 0): 0 { ... }` (colon syntax, same as TypeScript)
300
+ - **Safety markers**: `!` = unsafe (skip validation), `?` = safe (explicit validation)
301
+ - **Mode defaults**: Native TJS has all modes ON by default (`TjsEquals`, `TjsClass`, `TjsDate`, `TjsNoeval`, `TjsNoVar`, `TjsStandard`). TS-originated code (`fromTS`) and AJS/VM code get modes OFF. `TjsCompat` directive explicitly disables all modes. `TjsStrict` enables all modes (useful for TS-originated code opting in).
302
+ - **Bang access**: `x!.foo` — returns MonadicError if `x` is null/undefined, otherwise bare `x.foo`. Chains propagate: `x!.foo!.bar`.
303
+ - **Type/Generic/FunctionPredicate**: Three declaration forms for runtime type predicates
304
+ - **`const!`**: Compile-time immutability, zero runtime cost
305
+ - **Equality**: `==`/`!=` = structural equality by default in native TJS (via `Is`/`IsNot`), `===`/`!==` = identity
306
+ - **Polymorphic functions**: Multiple same-name declarations merge into arity/type dispatcher
307
+ - **`extend` blocks**: Local class extensions without prototype pollution
308
+ - **WASM blocks**: Inline WebAssembly compiled at transpile time, with SIMD intrinsics and `wasmBuffer()` zero-copy arrays
309
+ - **`@tjs` annotations**: `/* @tjs ... */` comments in TS files enrich TJS output
560
310
 
561
- Point(3, 4) // variant 1
562
- Point({ x: 10, y: 20 }) // variant 2 (both produce correct instanceof)
563
- ```
564
-
565
- The first constructor becomes the real JS constructor; additional variants become factory functions using `Object.create`.
566
-
567
- #### Local Class Extensions
568
-
569
- Add methods to built-in types without prototype pollution:
570
-
571
- ```typescript
572
- extend String {
573
- capitalize() { return this[0].toUpperCase() + this.slice(1) }
574
- }
575
-
576
- extend Array {
577
- last() { return this[this.length - 1] }
578
- }
579
-
580
- 'hello'.capitalize() // 'Hello' — rewritten to __ext_String.capitalize.call('hello')
581
- [1, 2, 3].last() // 3
582
- ```
583
-
584
- - Methods are rewritten to `.call()` at transpile time for known-type receivers (zero overhead)
585
- - Runtime fallback via `registerExtension()`/`resolveExtension()` for unknown types
586
- - Arrow functions rejected (need `this` binding)
587
- - Multiple `extend` blocks for same type merge left-to-right
588
- - File-local only — no cross-module leaking
589
-
590
- ## WASM Blocks
591
-
592
- TJS supports inline WebAssembly for performance-critical code. WASM blocks are compiled at transpile time and embedded as base64 in the output.
593
-
594
- ### Syntax
311
+ #### Runtime Configuration
595
312
 
596
313
  ```typescript
597
- const add = wasm (a: i32, b: i32) -> i32 {
598
- local.get $a
599
- local.get $b
600
- i32.add
601
- }
602
- ```
314
+ import { configure } from 'tjs-lang/lang'
603
315
 
604
- ### Features
605
-
606
- - **Transpile-time compilation**: WASM bytecode is generated during transpilation, not at runtime
607
- - **WAT comments**: Human-readable WebAssembly Text format is included as comments above the base64
608
- - **Type-safe**: Parameters and return types are validated
609
- - **Self-contained**: Compiled WASM is embedded in output JS, no separate .wasm files needed
610
-
611
- ### Output Example
612
-
613
- The transpiler generates code like:
614
-
615
- ```javascript
616
- /*
617
- * WASM Block: add
618
- * WAT (WebAssembly Text):
619
- * (func $add (param $a i32) (param $b i32) (result i32)
620
- * local.get 0
621
- * local.get 1
622
- * i32.add
623
- * )
624
- */
625
- const add = await (async () => {
626
- const bytes = Uint8Array.from(atob('AGFzbQEAAAA...'), (c) => c.charCodeAt(0))
627
- const { instance } = await WebAssembly.instantiate(bytes)
628
- return instance.exports.fn
629
- })()
316
+ configure({ logTypeErrors: true }) // Log type errors to console
317
+ configure({ throwTypeErrors: true }) // Throw instead of return (debugging)
318
+ configure({ callStacks: true }) // Track call stacks in errors (~2x overhead)
319
+ configure({ trackErrors: false }) // Disable error history (on by default)
630
320
  ```
631
321
 
632
- ### SIMD Intrinsics (f32x4)
322
+ #### Error History
633
323
 
634
- WASM blocks support explicit SIMD via `f32x4_*` intrinsics:
324
+ Type errors are tracked in a ring buffer (on by default, zero cost on happy path):
635
325
 
636
326
  ```typescript
637
- const scale = wasm (arr: Float32Array, len: 0, factor: 0.0) -> 0 {
638
- let s = f32x4_splat(factor)
639
- for (let i = 0; i < len; i += 4) {
640
- let off = i * 4
641
- let v = f32x4_load(arr, off)
642
- f32x4_store(arr, off, f32x4_mul(v, s))
643
- }
644
- } fallback {
645
- for (let i = 0; i < len; i++) arr[i] *= factor
646
- }
327
+ __tjs.errors() // recent MonadicErrors (newest last, max 64)
328
+ __tjs.clearErrors() // returns and clears the buffer
329
+ __tjs.getErrorCount() // total since last clear (survives buffer wrap)
647
330
  ```
648
331
 
649
- Available: `f32x4_load`, `f32x4_store`, `f32x4_splat`, `f32x4_extract_lane`, `f32x4_replace_lane`, `f32x4_add`, `f32x4_sub`, `f32x4_mul`, `f32x4_div`, `f32x4_neg`, `f32x4_sqrt`.
332
+ Use for debugging (find silent failures), testing (`clearErrors()` run → check), and monitoring.
650
333
 
651
- ### Zero-Copy Arrays: `wasmBuffer()`
334
+ #### Standalone JS Output
652
335
 
653
- `wasmBuffer(Constructor, length)` allocates typed arrays directly in WASM linear memory. When passed to a `wasm {}` block, these arrays are zero-copy — no marshalling overhead.
654
-
655
- ```typescript
656
- // Allocate in WASM memory (zero-copy when passed to wasm blocks)
657
- const xs = wasmBuffer(Float32Array, 50000)
658
-
659
- // Works like a normal Float32Array from JS
660
- xs[0] = 3.14
661
- for (let i = 0; i < xs.length; i++) xs[i] = Math.random()
662
-
663
- // Zero-copy in WASM blocks — data is already in WASM memory
664
- function process(! xs: Float32Array, len: 0, delta: 0.0) {
665
- wasm {
666
- let vd = f32x4_splat(delta)
667
- for (let i = 0; i < len; i += 4) {
668
- let off = i * 4
669
- f32x4_store(xs, off, f32x4_add(f32x4_load(xs, off), vd))
670
- }
671
- } fallback {
672
- for (let i = 0; i < len; i++) xs[i] += delta
673
- }
674
- }
675
-
676
- // After WASM runs, JS sees mutations immediately (same memory)
677
- ```
678
-
679
- - Regular `Float32Array` args are copied in before and out after each WASM call
680
- - `wasmBuffer` arrays skip both copies (detected via `buffer === wasmMemory.buffer`)
681
- - Uses a bump allocator — allocations persist for program lifetime (no deallocation)
682
- - All WASM blocks in a file share one `WebAssembly.Memory` (64MB / 1024 pages)
683
- - Supports `Float32Array`, `Float64Array`, `Int32Array`, `Uint8Array`
684
-
685
- ### Current Limitations
686
-
687
- - No imports/exports beyond the function itself
688
- - `wasmBuffer` allocations are permanent (bump allocator, no free)
336
+ Emitted `.js` files work without any runtime setup. Each file includes an inline
337
+ minimal runtime as fallback — only the functions actually used are included (~500
338
+ bytes for a basic validated function). If `globalThis.__tjs` exists (shared runtime),
339
+ it's used instead.
689
340
 
690
341
  ## Dependencies
691
342
 
@@ -731,7 +382,7 @@ Both `llmBattery` and `vector` can be `undefined`/`null` if LM Studio isn't avai
731
382
 
732
383
  ### Bun Plugin
733
384
 
734
- `bunfig.toml` preloads `src/bun-plugin/tjs-plugin.ts` which enables importing `.tjs` files directly in bun. It also aliases `tjs-lang` to `./src/index.ts` for local development (monorepo-style resolution).
385
+ `bunfig.toml` preloads `src/bun-plugin/tjs-plugin.ts` which enables importing `.tjs` files directly in bun (transpiled on-the-fly). It also aliases `tjs-lang` to `./src/index.ts` for local development, so `import { tjs } from 'tjs-lang'` resolves to the source tree without needing `npm link` or a published package.
735
386
 
736
387
  ### Code Style
737
388
 
@@ -759,29 +410,41 @@ The `docs/` directory contains real documentation (markdown), not build artifact
759
410
 
760
411
  - `DOCS-TJS.md` — TJS language guide
761
412
  - `DOCS-AJS.md` — AJS runtime guide
413
+ - `TJS-FOR-JS.md` — TJS guide for JavaScript developers (syntax differences, gotchas)
414
+ - `TJS-FOR-TS.md` — TJS guide for TypeScript developers (migration, interop)
762
415
  - `CONTEXT.md` — Architecture deep dive
763
- - `AGENTS.md` — Agent workflow instructions (issue tracking with `bd`, mandatory push-before-done). **Critical**: work is NOT complete until `git push` succeeds; use `bd ready` to find work, `bd close <id>` to complete
416
+ - `AGENTS.md` — Agent workflow instructions (issue tracking with `bd`, mandatory push-before-done)
764
417
  - `PLAN.md` — Roadmap
765
418
 
419
+ ### Issue Tracking with `bd`
420
+
421
+ The project uses `bd` (beads) for issue tracking. Key commands:
422
+
423
+ ```bash
424
+ bd ready # Find available work
425
+ bd show <id> # View issue details
426
+ bd update <id> --status in_progress # Claim work
427
+ bd close <id> # Complete work
428
+ bd sync # Sync with git
429
+ ```
430
+
431
+ **Critical rule**: Work is NOT complete until `git push` succeeds. Never stop before pushing — work stranded locally is work lost. If push fails, resolve and retry.
432
+
766
433
  ### Known Gotcha: `tjs()` Returns an Object, Not a String
767
434
 
768
435
  `tjs(source)` returns `{ code, types, metadata, testResults, ... }`. Use `.code` to get the transpiled JavaScript string. This is a common mistake.
769
436
 
770
- ### Known Gotcha: Running Emitted TJS Code in Tests
437
+ ### Running Emitted TJS Code
771
438
 
772
- Transpiled TJS code requires `globalThis.__tjs` to be set up with `createRuntime()` before execution:
439
+ Emitted JS works standalone no setup required. Each file includes an inline
440
+ runtime fallback. If you want the shared runtime (e.g. for `isMonadicError` to
441
+ work across files), install it first:
773
442
 
774
443
  ```typescript
775
- import { createRuntime } from '../lang/runtime'
776
-
777
- const saved = globalThis.__tjs
778
- globalThis.__tjs = createRuntime()
779
- try {
780
- const fn = new Function(result.code + '\nreturn fnName')()
781
- // ... test fn
782
- } finally {
783
- globalThis.__tjs = saved
784
- }
785
- ```
444
+ import { installRuntime, createRuntime } from '../lang/runtime'
445
+ installRuntime() // or: globalThis.__tjs = createRuntime()
786
446
 
787
- A `{ standalone: true }` option to inline the ~1KB runtime is planned but not yet implemented.
447
+ const fn = new Function(result.code + '\nreturn fnName')()
448
+ fn('valid') // works
449
+ fn(42) // returns MonadicError (not thrown)
450
+ ```