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.
- package/CLAUDE.md +85 -422
- package/README.md +15 -82
- package/bin/benchmarks.ts +7 -7
- package/bin/dev.ts +2 -1
- package/demo/autocomplete.test.ts +1 -1
- package/demo/docs.json +744 -48
- package/demo/src/demo-nav.ts +5 -5
- package/demo/src/index.ts +28 -36
- package/demo/src/module-sw.ts +1 -1
- package/demo/src/playground-shared.ts +17 -17
- package/demo/src/playground.ts +13 -1
- package/demo/src/style.ts +4 -1
- package/demo/src/tjs-playground.ts +5 -5
- package/demo/src/user-store.ts +2 -1
- package/demo/static/favicon.svg +17 -24
- package/demo/static/tosi-platform.json +9304 -0
- package/dist/index.js +158 -156
- package/dist/index.js.map +14 -13
- package/dist/scripts/compat-effect.d.ts +16 -0
- package/dist/scripts/compat-kysely.d.ts +13 -0
- package/dist/scripts/compat-radash.d.ts +13 -0
- package/dist/scripts/compat-superstruct.d.ts +13 -0
- package/dist/scripts/compat-ts-pattern.d.ts +13 -0
- package/dist/scripts/compat-zod.d.ts +12 -0
- package/dist/src/lang/emitters/from-ts.d.ts +1 -1
- package/dist/src/lang/emitters/js-tests.d.ts +4 -0
- package/dist/src/lang/emitters/js.d.ts +2 -2
- package/dist/src/lang/index.d.ts +1 -0
- package/dist/src/lang/json-schema.d.ts +40 -0
- package/dist/src/lang/parser-transforms.d.ts +14 -0
- package/dist/src/lang/runtime.d.ts +39 -6
- package/dist/src/types/Type.d.ts +5 -0
- package/dist/tjs-full.js +158 -156
- package/dist/tjs-full.js.map +14 -13
- package/dist/tjs-vm.js +44 -43
- package/dist/tjs-vm.js.map +5 -5
- package/docs/README.md +21 -20
- package/docs/WASM-QUICKSTART.md +283 -0
- package/docs/diagrams/architecture-shift.svg +117 -0
- package/docs/diagrams/compile-runtime.svg +130 -0
- package/docs/diagrams/icon-riff-1.svg +55 -0
- package/docs/diagrams/icon-riff-2.svg +62 -0
- package/docs/diagrams/icon-riff-3.svg +61 -0
- package/docs/diagrams/platform-overview.svg +114 -0
- package/docs/diagrams/safe-eval.svg +147 -0
- package/docs/eval-v4/arch-comparison.svg +277 -0
- package/docs/eval-v4/bundler-tree.svg +250 -0
- package/docs/eval-v4/http-lifecycle.svg +148 -0
- package/docs/function-predicate-design.md +8 -8
- package/docs/native-engine-integration.md +2 -2
- package/editors/codemirror/autocomplete.test.ts +29 -29
- package/package.json +10 -4
- package/src/cli/commands/convert.test.ts +11 -8
- package/src/cli/tjs.ts +1 -1
- package/src/lang/codegen.test.ts +117 -112
- package/src/lang/docs.test.ts +22 -22
- package/src/lang/docs.ts +5 -8
- package/src/lang/emitters/dts.test.ts +13 -13
- package/src/lang/emitters/from-ts.ts +36 -9
- package/src/lang/emitters/js-tests.ts +143 -28
- package/src/lang/emitters/js.ts +49 -28
- package/src/lang/features.test.ts +259 -43
- package/src/lang/from-ts.test.ts +3 -3
- package/src/lang/function-predicate.test.ts +1 -1
- package/src/lang/index.ts +8 -47
- package/src/lang/json-schema.test.ts +261 -0
- package/src/lang/json-schema.ts +167 -0
- package/src/lang/parser-params.ts +28 -44
- package/src/lang/parser-transforms.ts +255 -0
- package/src/lang/parser.test.ts +32 -13
- package/src/lang/parser.ts +49 -11
- package/src/lang/perf.test.ts +11 -11
- package/src/lang/roundtrip.test.ts +3 -3
- package/src/lang/runtime.test.ts +167 -0
- package/src/lang/runtime.ts +234 -46
- package/src/lang/transpiler.test.ts +21 -21
- package/src/lang/typescript-syntax.test.ts +11 -9
- package/src/types/Type.ts +38 -1
- package/src/use-cases/bootstrap.test.ts +7 -7
- package/src/use-cases/client-server.test.ts +1 -1
- package/src/use-cases/malicious-actor.test.ts +1 -1
- package/src/use-cases/rag-processor.test.ts +1 -1
- package/src/use-cases/sophisticated-agents.test.ts +2 -2
- package/src/use-cases/transpiler-llm.test.ts +1 -1
- package/src/use-cases/unbundled-imports.test.ts +9 -9
- 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 '
|
|
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 '
|
|
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 '
|
|
165
|
-
import { tjs } from '
|
|
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
|
|
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
|
-
|
|
295
|
+
Full syntax documentation is in [`CLAUDE-TJS-SYNTAX.md`](CLAUDE-TJS-SYNTAX.md). Key concepts:
|
|
445
296
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
TjsClass
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
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
|
-
|
|
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
|
-
|
|
598
|
-
local.get $a
|
|
599
|
-
local.get $b
|
|
600
|
-
i32.add
|
|
601
|
-
}
|
|
602
|
-
```
|
|
314
|
+
import { configure } from 'tjs-lang/lang'
|
|
603
315
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
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
|
-
|
|
322
|
+
#### Error History
|
|
633
323
|
|
|
634
|
-
|
|
324
|
+
Type errors are tracked in a ring buffer (on by default, zero cost on happy path):
|
|
635
325
|
|
|
636
326
|
```typescript
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
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
|
-
|
|
332
|
+
Use for debugging (find silent failures), testing (`clearErrors()` → run → check), and monitoring.
|
|
650
333
|
|
|
651
|
-
|
|
334
|
+
#### Standalone JS Output
|
|
652
335
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
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
|
|
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)
|
|
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
|
-
###
|
|
437
|
+
### Running Emitted TJS Code
|
|
771
438
|
|
|
772
|
-
|
|
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
|
-
|
|
447
|
+
const fn = new Function(result.code + '\nreturn fnName')()
|
|
448
|
+
fn('valid') // works
|
|
449
|
+
fn(42) // returns MonadicError (not thrown)
|
|
450
|
+
```
|