tjs-lang 0.6.8 → 0.6.10

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/demo/docs.json CHANGED
@@ -55,7 +55,7 @@
55
55
  "type": "example",
56
56
  "group": "advanced",
57
57
  "order": 16,
58
- "code": "/**\n * # Testing Private Functions\n *\n * This is the killer feature of inline tests:\n * You can test functions WITHOUT exporting them.\n *\n * Traditional testing requires you to either:\n * - Export internal helpers (pollutes your API)\n * - Test only through public interface (incomplete coverage)\n * - Use hacks like rewire/proxyquire (brittle)\n *\n * TJS inline tests have full access to the module scope.\n * Test everything. Export only what you need.\n */\n\n// ============================================================\n// PRIVATE HELPERS (not exported, but fully testable!)\n// ============================================================\n\n// Private: Email validation regex\nconst EMAIL_REGEX = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n\n// Private: Validate email format\nfunction isValidEmail(email: '') -> true {\n return EMAIL_REGEX.test(email)\n}\n\n// Private: Sanitize user input\nfunction sanitize(input: '') -> '' {\n return input.trim().toLowerCase()\n}\n\n// Private: Generate a unique ID\nfunction generateId(prefix: 'user') -> '' {\n return prefix + '_' + Math.random().toString(36).slice(2, 10)\n}\n\n// Private: Hash password (simplified for demo)\nfunction hashPassword(password: '') -> '' {\n let hash = 0\n for (let i = 0; i < password.length; i++) {\n hash = ((hash << 5) - hash) + password.charCodeAt(i)\n hash = hash & hash\n }\n return 'hashed_' + Math.abs(hash).toString(16)\n}\n\n// Private: Check password strength\nfunction isStrongPassword(password: '') -> { strong: true, issues: [''] } {\n const issues = []\n if (password.length < 8) issues.push('Must be at least 8 characters')\n if (!/[A-Z]/.test(password)) issues.push('Must contain uppercase letter')\n if (!/[a-z]/.test(password)) issues.push('Must contain lowercase letter')\n if (!/[0-9]/.test(password)) issues.push('Must contain a number')\n return { strong: issues.length === 0, issues }\n}\n\n// ============================================================\n// PUBLIC API (this is all that gets exported)\n// ============================================================\n\nexport function createUser(input: { email: '', password: '' })\n -> { id: '', email: '', passwordHash: '' } | { error: '', code: 0 } {\n\n // Validate email (using private helper)\n const cleanEmail = sanitize(input.email)\n if (!isValidEmail(cleanEmail)) {\n return { error: 'Invalid email format', code: 400 }\n }\n\n // Validate password (using private helper)\n const strength = isStrongPassword(input.password)\n if (!strength.strong) {\n return { error: strength.issues.join(', '), code: 400 }\n }\n\n // Create user (using private helpers)\n return {\n id: generateId('user'),\n email: cleanEmail,\n passwordHash: hashPassword(input.password)\n }\n}\n\n// ============================================================\n// TESTS - Full access to private functions!\n// ============================================================\n\n// --- Test private email validation ---\ntest 'isValidEmail accepts valid emails' {\n expect(isValidEmail('test@example.com')).toBe(true)\n expect(isValidEmail('user.name+tag@domain.co.uk')).toBe(true)\n}\n\ntest 'isValidEmail rejects invalid emails' {\n expect(isValidEmail('not-an-email')).toBe(false)\n expect(isValidEmail('@nodomain.com')).toBe(false)\n expect(isValidEmail('spaces in@email.com')).toBe(false)\n}\n\n// --- Test private sanitization ---\ntest 'sanitize trims and lowercases' {\n expect(sanitize(' HELLO ')).toBe('hello')\n expect(sanitize(' Test@Email.COM ')).toBe('test@email.com')\n}\n\n// --- Test private ID generation ---\ntest 'generateId creates prefixed unique IDs' {\n const id1 = generateId('user')\n const id2 = generateId('user')\n expect(id1.startsWith('user_')).toBe(true)\n expect(id1 !== id2).toBe(true) // unique each time\n}\n\ntest 'generateId respects prefix' {\n expect(generateId('post').startsWith('post_')).toBe(true)\n expect(generateId('comment').startsWith('comment_')).toBe(true)\n}\n\n// --- Test private password hashing ---\ntest 'hashPassword is deterministic' {\n const hash1 = hashPassword('secret123')\n const hash2 = hashPassword('secret123')\n expect(hash1).toBe(hash2)\n}\n\ntest 'hashPassword produces different hashes for different inputs' {\n const hash1 = hashPassword('password1')\n const hash2 = hashPassword('password2')\n expect(hash1 !== hash2).toBe(true)\n}\n\n// --- Test private password strength checker ---\ntest 'isStrongPassword rejects weak passwords' {\n const result = isStrongPassword('weak')\n expect(result.strong).toBe(false)\n expect(result.issues.length).toBeGreaterThan(0)\n}\n\ntest 'isStrongPassword accepts strong passwords' {\n const result = isStrongPassword('MyStr0ngP@ss!')\n expect(result.strong).toBe(true)\n expect(result.issues.length).toBe(0)\n}\n\ntest 'isStrongPassword lists specific issues' {\n const noUpper = isStrongPassword('lowercase123')\n expect(noUpper.issues).toContain('Must contain uppercase letter')\n\n const noLower = isStrongPassword('UPPERCASE123')\n expect(noLower.issues).toContain('Must contain lowercase letter')\n\n const noNumber = isStrongPassword('NoNumbers!')\n expect(noNumber.issues).toContain('Must contain a number')\n\n const tooShort = isStrongPassword('Ab1!')\n expect(tooShort.issues).toContain('Must be at least 8 characters')\n}\n\n// --- Test the public API (integration) ---\ntest 'createUser validates email' {\n const result = createUser({ email: 'invalid', password: 'StrongPass1!' })\n expect(result.error).toBe('Invalid email format')\n}\n\ntest 'createUser validates password strength' {\n const result = createUser({ email: 'test@test.com', password: 'weak' })\n expect(result.error).toBeTruthy()\n}\n\ntest 'createUser succeeds with valid input' {\n const result = createUser({\n email: ' Test@Example.COM ',\n password: 'MyStr0ngPass!'\n })\n expect(result.id).toBeTruthy()\n expect(result.email).toBe('test@example.com') // sanitized\n expect(result.passwordHash.startsWith('hashed_')).toBe(true)\n}\n\n// ============================================================\n// DEMO OUTPUT\n// ============================================================\n\nconsole.log('=== Testing Private Functions Demo ===\\n')\nconsole.log('The functions isValidEmail, sanitize, generateId,')\nconsole.log('hashPassword, and isStrongPassword are all PRIVATE.')\nconsole.log('They are NOT exported. But we tested them all!\\n')\n\nconsole.log(\"Try this in Jest/Vitest without exporting them. You can't.\")\nconsole.log(\"You'd have to either pollute your API or leave them untested.\\n\")\n\nconsole.log('TJS inline tests: Full coverage. Clean exports.\\n')\n\n// Show the public API working\nconst user = createUser({ email: 'demo@example.com', password: 'SecurePass123!' })\nconsole.log('Created user:', user)",
58
+ "code": "/**\n * # Testing Private Functions\n *\n * This is the killer feature of inline tests:\n * You can test functions WITHOUT exporting them.\n *\n * Traditional testing requires you to either:\n * - Export internal helpers (pollutes your API)\n * - Test only through public interface (incomplete coverage)\n * - Use hacks like rewire/proxyquire (brittle)\n *\n * TJS inline tests have full access to the module scope.\n * Test everything. Export only what you need.\n */\n\n// ============================================================\n// PRIVATE HELPERS (not exported, but fully testable!)\n// ============================================================\n\n// Private: Email validation regex\nconst EMAIL_REGEX = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n\n// Private: Validate email format\nfunction isValidEmail(email: '') -> false {\n return EMAIL_REGEX.test(email)\n}\n\n// Private: Sanitize user input\nfunction sanitize(input: '') -> '' {\n return input.trim().toLowerCase()\n}\n\n// Private: Generate a unique ID\nfunction generateId(prefix: 'user') -! '' {\n return prefix + '_' + Math.random().toString(36).slice(2, 10)\n}\n\n// Private: Hash password (simplified for demo)\nfunction hashPassword(password: '') -> 'hashed_0' {\n let hash = 0\n for (let i = 0; i < password.length; i++) {\n hash = ((hash << 5) - hash) + password.charCodeAt(i)\n hash = hash & hash\n }\n return 'hashed_' + Math.abs(hash).toString(16)\n}\n\n// Private: Check password strength\nfunction isStrongPassword(password: '') -! { strong: true, issues: [''] } {\n const issues = []\n if (password.length < 8) issues.push('Must be at least 8 characters')\n if (!/[A-Z]/.test(password)) issues.push('Must contain uppercase letter')\n if (!/[a-z]/.test(password)) issues.push('Must contain lowercase letter')\n if (!/[0-9]/.test(password)) issues.push('Must contain a number')\n return { strong: issues.length === 0, issues }\n}\n\n// ============================================================\n// PUBLIC API (this is all that gets exported)\n// ============================================================\n\nexport function createUser(input: { email: '', password: '' })\n -! { id: '', email: '', passwordHash: '' } | { error: '', code: 0 } {\n\n // Validate email (using private helper)\n const cleanEmail = sanitize(input.email)\n if (!isValidEmail(cleanEmail)) {\n return { error: 'Invalid email format', code: 400 }\n }\n\n // Validate password (using private helper)\n const strength = isStrongPassword(input.password)\n if (!strength.strong) {\n return { error: strength.issues.join(', '), code: 400 }\n }\n\n // Create user (using private helpers)\n return {\n id: generateId('user'),\n email: cleanEmail,\n passwordHash: hashPassword(input.password)\n }\n}\n\n// ============================================================\n// TESTS - Full access to private functions!\n// ============================================================\n\n// --- Test private email validation ---\ntest 'isValidEmail accepts valid emails' {\n expect(isValidEmail('test@example.com')).toBe(true)\n expect(isValidEmail('user.name+tag@domain.co.uk')).toBe(true)\n}\n\ntest 'isValidEmail rejects invalid emails' {\n expect(isValidEmail('not-an-email')).toBe(false)\n expect(isValidEmail('@nodomain.com')).toBe(false)\n expect(isValidEmail('spaces in@email.com')).toBe(false)\n}\n\n// --- Test private sanitization ---\ntest 'sanitize trims and lowercases' {\n expect(sanitize(' HELLO ')).toBe('hello')\n expect(sanitize(' Test@Email.COM ')).toBe('test@email.com')\n}\n\n// --- Test private ID generation ---\ntest 'generateId creates prefixed unique IDs' {\n const id1 = generateId('user')\n const id2 = generateId('user')\n expect(id1.startsWith('user_')).toBe(true)\n expect(id1 !== id2).toBe(true) // unique each time\n}\n\ntest 'generateId respects prefix' {\n expect(generateId('post').startsWith('post_')).toBe(true)\n expect(generateId('comment').startsWith('comment_')).toBe(true)\n}\n\n// --- Test private password hashing ---\ntest 'hashPassword is deterministic' {\n const hash1 = hashPassword('secret123')\n const hash2 = hashPassword('secret123')\n expect(hash1).toBe(hash2)\n}\n\ntest 'hashPassword produces different hashes for different inputs' {\n const hash1 = hashPassword('password1')\n const hash2 = hashPassword('password2')\n expect(hash1 !== hash2).toBe(true)\n}\n\n// --- Test private password strength checker ---\ntest 'isStrongPassword rejects weak passwords' {\n const result = isStrongPassword('weak')\n expect(result.strong).toBe(false)\n expect(result.issues.length).toBeGreaterThan(0)\n}\n\ntest 'isStrongPassword accepts strong passwords' {\n const result = isStrongPassword('MyStr0ngP@ss!')\n expect(result.strong).toBe(true)\n expect(result.issues.length).toBe(0)\n}\n\ntest 'isStrongPassword lists specific issues' {\n const noUpper = isStrongPassword('lowercase123')\n expect(noUpper.issues).toContain('Must contain uppercase letter')\n\n const noLower = isStrongPassword('UPPERCASE123')\n expect(noLower.issues).toContain('Must contain lowercase letter')\n\n const noNumber = isStrongPassword('NoNumbers!')\n expect(noNumber.issues).toContain('Must contain a number')\n\n const tooShort = isStrongPassword('Ab1!')\n expect(tooShort.issues).toContain('Must be at least 8 characters')\n}\n\n// --- Test the public API (integration) ---\ntest 'createUser validates email' {\n const result = createUser({ email: 'invalid', password: 'StrongPass1!' })\n expect(result.error).toBe('Invalid email format')\n}\n\ntest 'createUser validates password strength' {\n const result = createUser({ email: 'test@test.com', password: 'weak' })\n expect(result.error).toBeTruthy()\n}\n\ntest 'createUser succeeds with valid input' {\n const result = createUser({\n email: ' Test@Example.COM ',\n password: 'MyStr0ngPass!'\n })\n expect(result.id).toBeTruthy()\n expect(result.email).toBe('test@example.com') // sanitized\n expect(result.passwordHash.startsWith('hashed_')).toBe(true)\n}\n\n// ============================================================\n// DEMO OUTPUT\n// ============================================================\n\nconsole.log('=== Testing Private Functions Demo ===\\n')\nconsole.log('The functions isValidEmail, sanitize, generateId,')\nconsole.log('hashPassword, and isStrongPassword are all PRIVATE.')\nconsole.log('They are NOT exported. But we tested them all!\\n')\n\nconsole.log(\"Try this in Jest/Vitest without exporting them. You can't.\")\nconsole.log(\"You'd have to either pollute your API or leave them untested.\\n\")\n\nconsole.log('TJS inline tests: Full coverage. Clean exports.\\n')\n\n// Show the public API working\nconst user = createUser({ email: 'demo@example.com', password: 'SecurePass123!' })\nconsole.log('Created user:', user)",
59
59
  "language": "tjs",
60
60
  "description": "Test internals without exporting them - the killer feature"
61
61
  },
@@ -79,7 +79,7 @@
79
79
  "type": "example",
80
80
  "group": "basics",
81
81
  "order": 2,
82
- "code": "/*#\n## Required vs Optional Parameters\n\nIn TJS, the punctuation tells you everything:\n\n| Syntax | Meaning |\n|--------|---------|\n| `param: 'value'` | **Required** - must be provided |\n| `param = 'value'` | **Optional** - defaults to value |\n\nThe example value after `:` or `=` defines the type.\n*/\ntest 'requires name and email' {\n const user = createUser('Alice', 'alice@test.com')\n expect(user.name).toBe('Alice')\n expect(user.age).toBe(0) // default\n}\n\nfunction createUser(\n name: 'anonymous',\n email: 'user@example.com',\n age = 0,\n admin = false\n) -> { name: '', email: '', age: 0, admin: false } {\n return { name, email, age, admin }\n}\n\n// Check the metadata\nconsole.log('Params:', createUser.__tjs.params)\ncreateUser('Alice', 'alice@example.com')",
82
+ "code": "/*#\n## Required vs Optional Parameters\n\nIn TJS, the punctuation tells you everything:\n\n| Syntax | Meaning |\n|--------|---------|\n| `param: 'value'` | **Required** - must be provided |\n| `param = 'value'` | **Optional** - defaults to value |\n\nThe example value after `:` or `=` defines the type.\n*/\ntest 'requires name and email' {\n const user = createUser('Alice', 'alice@test.com')\n expect(user.name).toBe('Alice')\n expect(user.age).toBe(0) // default\n}\n\nfunction createUser(\n name: 'anonymous',\n email: 'user@example.com',\n age = 0,\n admin = false\n) -> { name: 'anonymous', email: 'user@example.com', age: 0, admin: false } {\n return { name, email, age, admin }\n}\n\n// Check the metadata\nconsole.log('Params:', createUser.__tjs.params)\ncreateUser('Alice', 'alice@example.com')",
83
83
  "language": "tjs",
84
84
  "description": "Difference between : and = in parameters"
85
85
  },
@@ -91,7 +91,7 @@
91
91
  "type": "example",
92
92
  "group": "basics",
93
93
  "order": 3,
94
- "code": "/*#\n## Object Types\n\nObject shapes are defined by example:\n`{ first: '', last: '' }` means an object with string properties.\n\nThe return type `-> { x: 0, y: 0 }` is tested at transpile time!\n*/\ntest 'createPoint returns correct structure' {\n const p = createPoint(5, 10)\n expect(p.x).toBe(5)\n expect(p.y).toBe(10)\n}\n\nfunction getFullName(person: { first: '', last: '' }) -> 'Jane Doe' {\n return person.first + ' ' + person.last\n}\n\nfunction createPoint(x: 0, y: 0) -> { x: 0, y: 0 } {\n return { x, y }\n}\n\nfunction distance(p1: { x: 0, y: 0 }, p2: { x: 0, y: 0 }) -> 5 {\n const dx = p2.x - p1.x\n const dy = p2.y - p1.y\n return Math.sqrt(dx * dx + dy * dy)\n}\n\n// Usage - signature tests verify these at transpile time\nconst name = getFullName({ first: 'Jane', last: 'Doe' }) // -> 'Jane Doe'\nconst dist = distance({ x: 0, y: 0 }, { x: 3, y: 4 }) // -> 5\n\nconsole.log('Name:', name)\nconsole.log('Distance:', dist)",
94
+ "code": "/*#\n## Object Types\n\nObject shapes are defined by example:\n`{ first: '', last: '' }` means an object with string properties.\n\nThe return type `-> { x: 0, y: 0 }` is tested at transpile time!\n*/\ntest 'createPoint returns correct structure' {\n const p = createPoint(5, 10)\n expect(p.x).toBe(5)\n expect(p.y).toBe(10)\n}\n\nfunction getFullName(person: { first: '', last: '' }) -> ' ' {\n return person.first + ' ' + person.last\n}\n\nfunction createPoint(x: 0, y: 0) -> { x: 0, y: 0 } {\n return { x, y }\n}\n\nfunction distance(p1: { x: 0, y: 0 }, p2: { x: 0, y: 0 }) -> 0 {\n const dx = p2.x - p1.x\n const dy = p2.y - p1.y\n return Math.sqrt(dx * dx + dy * dy)\n}\n\n// Usage - signature tests verify these at transpile time\nconst name = getFullName({ first: 'Jane', last: 'Doe' }) // -> 'Jane Doe'\nconst dist = distance({ x: 0, y: 0 }, { x: 3, y: 4 }) // -> 5\n\nconsole.log('Name:', name)\nconsole.log('Distance:', dist)",
95
95
  "language": "tjs",
96
96
  "description": "Typed object parameters and returns"
97
97
  },
@@ -103,7 +103,7 @@
103
103
  "type": "example",
104
104
  "group": "basics",
105
105
  "order": 4,
106
- "code": "/*#\n## Array Types\n\nArray types use a single-element example:\n- `[0]` = array of numbers\n- `['']` = array of strings\n- `[{ x: 0 }]` = array of objects with shape { x: number }\n*/\ntest 'sum adds numbers' {\n expect(sum([1, 2, 3, 4])).toBe(10)\n}\n\ntest 'stats calculates correctly' {\n const s = stats([10, 20, 30])\n expect(s.min).toBe(10)\n expect(s.max).toBe(30)\n expect(s.avg).toBe(20)\n}\n\nfunction sum(numbers: [0]) -> 10 {\n return numbers.reduce((a, b) => a + b, 0)\n}\n\nfunction average(numbers: [0]) -> 20 {\n if (numbers.length === 0) return 0\n return sum(numbers) / numbers.length\n}\n\nfunction stats(data: [0]) -> { min: 10, max: 30, avg: 20 } {\n if (data.length === 0) {\n return { min: 0, max: 0, avg: 0 }\n }\n return {\n min: Math.min(...data),\n max: Math.max(...data),\n avg: average(data)\n }\n}\n\n// Signature test: stats([10, 20, 30]) -> { min: 10, max: 30, avg: 20 }\nstats([10, 20, 30])",
106
+ "code": "/*#\n## Array Types\n\nArray types use a single-element example:\n- `[0]` = array of numbers\n- `['']` = array of strings\n- `[{ x: 0 }]` = array of objects with shape { x: number }\n*/\ntest 'sum adds numbers' {\n expect(sum([1, 2, 3, 4])).toBe(10)\n}\n\ntest 'stats calculates correctly' {\n const s = stats([10, 20, 30])\n expect(s.min).toBe(10)\n expect(s.max).toBe(30)\n expect(s.avg).toBe(20)\n}\n\nfunction sum(numbers: [3, 7]) -> 10 {\n return numbers.reduce((a, b) => a + b, 0)\n}\n\nfunction average(numbers: [10, 30]) -> 20 {\n if (numbers.length === 0) return 0\n return sum(numbers) / numbers.length\n}\n\nfunction stats(data: [10, 20, 30]) -> { min: 10, max: 30, avg: 20 } {\n if (data.length === 0) {\n return { min: 0, max: 0, avg: 0 }\n }\n return {\n min: Math.min(...data),\n max: Math.max(...data),\n avg: average(data)\n }\n}",
107
107
  "language": "tjs",
108
108
  "description": "Working with typed arrays"
109
109
  },
@@ -151,7 +151,7 @@
151
151
  "group": "docs",
152
152
  "order": 0,
153
153
  "navTitle": "Documentation",
154
- "text": "<!--{\"section\": \"tjs\", \"group\": \"docs\", \"order\": 0, \"navTitle\": \"Documentation\"}-->\n\n# TJS: Typed JavaScript\n\n_Types as Examples. Zero Build. Runtime Metadata._\n\n---\n\n## What is TJS?\n\nTJS is a typed superset of JavaScript where **types are concrete values**, not abstract annotations.\n\n```typescript\n// TypeScript: abstract type annotation\nfunction greet(name: string): string\n\n// TJS: concrete example value\nfunction greet(name: 'World') -> '' { return `Hello, ${name}!` }\n```\n\nThe example `'World'` tells TJS that `name` is a string. The example `''` tells TJS the return type is a string. Types are inferred from the examples you provide.\n\nTJS transpiles to JavaScript with embedded `__tjs` metadata, enabling runtime type checking, autocomplete from live objects, and documentation generation.\n\n---\n\n## TJS is JavaScript\n\nTJS is **purely additive**. It adds type annotations, runtime validation, and metadata on top of standard JavaScript. It does not replace, intercept, or modify any existing JavaScript semantics.\n\n**Everything you know about JavaScript still works:**\n\n- **Proxies** — fully supported. TJS never intercepts property access. `__tjs` metadata is a plain property assignment on the function object; it doesn't interfere with Proxy traps. The `[tjsEquals]` symbol protocol is specifically designed for Proxy-friendly custom equality.\n- **WeakMap, WeakSet, Map, Set** — all unchanged. TJS doesn't wrap or validate collection internals.\n- **Closures, Promises, async/await** — work identically to JS.\n- **Prototype chains** — preserved. `wrapClass()` uses a Proxy only on the class constructor (to allow calling without `new`), not on instances.\n- **Module semantics** — TJS preserves ES module `import`/`export` exactly. Lazy getters, circular dependencies, and re-exports work the same as in JS.\n- **`this` binding** — unchanged. Arrow functions, `.bind()`, `.call()`, `.apply()` all work normally.\n- **Regular expressions, JSON, Math, Date** — all standard built-ins are available and unmodified (though `TjsDate` directive can optionally ban `Date` in favor of safer alternatives).\n\n**What TJS adds (and when):**\n\n| Addition | When | Overhead |\n| ---------------------- | ----------------------------------------- | ----------------------------- |\n| Parameter validation | Function entry (unless `!` unsafe) | ~1.5x on that function |\n| Return type validation | Function exit (only with `safety all`) | ~1.5x on that function |\n| `__tjs` metadata | Transpile time | Zero runtime cost |\n| `wrapClass` Proxy | Class declaration (with `TjsClass`) | One-time, on constructor only |\n| Structural equality | Only when `==`/`!=` used with `TjsEquals` | Per-comparison |\n\nIf TJS doesn't understand something in your code, it passes it through unchanged. There is no \"TJS runtime\" that interposes between your code and the JS engine — just the inline checks you can see in the transpiled output.\n\n---\n\n## The Compiler\n\nTJS compiles in the browser. No webpack, no node_modules, no build server.\n\n```typescript\nimport { tjs } from 'tjs-lang'\n\nconst code = tjs`\n function add(a: 0, b: 0) -> 0 {\n return a + b\n }\n`\n\n// Returns transpiled JavaScript with __tjs metadata\n```\n\nYou can also use the CLI:\n\n```bash\nbun src/cli/tjs.ts check file.tjs # Parse and type check\nbun src/cli/tjs.ts run file.tjs # Transpile and execute\nbun src/cli/tjs.ts emit file.tjs # Output transpiled JS\nbun src/cli/tjs.ts types file.tjs # Output type metadata\n```\n\n---\n\n## Syntax\n\n### Parameter Types (Colon Syntax)\n\n> **Not TypeScript.** TJS colon syntax looks like TypeScript but has different\n> semantics. The value after `:` is a **concrete example**, not a type name.\n> Write `name: 'Alice'` (example value), not `name: string` (type name).\n> TJS infers the type from the example: `'Alice'` → string, `0` → integer,\n> `true` → boolean.\n\nRequired parameters use colon syntax with an example value:\n\n```typescript\nfunction greet(name: 'Alice') {} // name is required, type: string\nfunction calculate(value: 0) {} // value is required, type: integer\nfunction measure(rate: 0.0) {} // rate is required, type: number (float)\nfunction count(n: +0) {} // n is required, type: non-negative integer\nfunction toggle(flag: true) {} // flag is required, type: boolean\n```\n\n### Numeric Types\n\nTJS distinguishes three numeric types using valid JavaScript syntax:\n\n```typescript\nfunction process(\n rate: 3.14, // number (float) -- has a decimal point\n count: 42, // integer -- whole number, no decimal\n index: +0 // non-negative integer -- prefixed with +\n) {}\n```\n\n| You Write | Type Inferred | Runtime Validation |\n| --------- | ---------------------- | ------------------------------- |\n| `3.14` | `number` (float) | `typeof x === 'number'` |\n| `0.0` | `number` (float) | `typeof x === 'number'` |\n| `42` | `integer` | `Number.isInteger(x)` |\n| `0` | `integer` | `Number.isInteger(x)` |\n| `+20` | `non-negative integer` | `Number.isInteger(x) && x >= 0` |\n| `+0` | `non-negative integer` | `Number.isInteger(x) && x >= 0` |\n| `-5` | `integer` | `Number.isInteger(x)` |\n| `-3.5` | `number` (float) | `typeof x === 'number'` |\n\nAll of these are valid JavaScript expressions. TJS reads the syntax more\ncarefully to give you finer-grained type checking than JS or TypeScript\nprovide natively.\n\n### Optional Parameters (Default Values)\n\nOptional parameters use `=` with a default value:\n\n```typescript\nfunction greet(name = 'World') {} // name is optional, defaults to 'World'\nfunction calculate(value = 0) {} // value is optional, defaults to 0 (integer)\n```\n\n### TypeScript-Style Optional (`?:`)\n\nTJS supports `?:` for compatibility, but consider it a migration aid rather than idiomatic TJS:\n\n```typescript\nfunction greet(name?: '') {} // same as name = ''\n```\n\n**Why `?:` is an antipattern.** In TypeScript, `?:` creates a three-state parameter\n(`value | undefined | missing`) that forces every function body to handle the absent case:\n\n```typescript\n// TypeScript — every caller and callee must reason about undefined\nfunction greet(name?: string) {\n const safeName = name ?? 'World' // defensive check required\n return `Hello, ${safeName}!`\n}\n```\n\nTJS offers two better alternatives:\n\n**1. Safe defaults** — the parameter always has a value, no branching needed:\n\n```typescript\nfunction greet(name = 'World') {\n return `Hello, ${name}!` // name is always a string\n}\n```\n\n**2. Polymorphic functions** — separate signatures for separate behavior:\n\n```typescript\nfunction greet() {\n return 'Hello, World!'\n}\nfunction greet(name: '') {\n return `Hello, ${name}!`\n}\n```\n\nBoth approaches eliminate the `undefined` state entirely. The function body\nnever needs a null check because the type system guarantees a valid value\nat every call site. This is simpler to write, simpler to read, and produces\ntighter runtime validation.\n\n### Object Parameters\n\nObject shapes are defined by example:\n\n```typescript\nfunction createUser(user: { name: ''; age: 0 }) {}\n// user must be an object with string name and number age\n```\n\n### Nullable Types\n\nUse `|` for union with null:\n\n```typescript\nfunction find(id: 0 | null) {} // number or null\n```\n\n### Rest Parameters\n\nRest params use `:` with an array example. The annotation is stripped from\nthe JS output (JS doesn't allow defaults on rest params) but captured in\n`__tjs` metadata:\n\n```typescript\nfunction sum(...nums: [1, 2, 3]) -> 6 {\n return nums.reduce((a = 0, b: 0) => a + b, 0)\n}\n\nfunction mean(...values: [1.0, 2.0, 3.0, 2.0]) -> 2.0 {\n return values.length\n ? values.reduce((sum = 0.0, x: 1.0) => sum + x) / values.length\n : 0.0\n}\n```\n\nSignature tests work with rest params — the example array elements are\nspread as individual arguments. `mean(1.0, 2.0, 3.0, 2.0)` is called\nand its result checked against the `-> 2.0` expected return.\n\nThe array example tells TJS the element type. `[0]` means \"array of\nintegers\", `[1.0, 2.0]` means \"array of numbers (floats)\".\n\n**Heterogeneous arrays** infer a union item type:\n\n```typescript\nfunction log(...args: ['info', 42, true]) {}\n// args type: array<string | integer | boolean>\n```\n\n### Return Types (Arrow Syntax)\n\nReturn types use `->`:\n\n```typescript\nfunction add(a: 0, b: 0) -> 0 {\n return a + b\n}\n\nfunction getUser(id: 0) -> { name: '', age: 0 } {\n return { name: 'Alice', age: 30 }\n}\n```\n\n### Array Types\n\nArrays use bracket syntax with an example element:\n\n```typescript\nfunction sum(numbers: [0]) -> 0 { // array of numbers\n return numbers.reduce((a, b) => a + b, 0)\n}\n\nfunction names(users: [{ name: '' }]) { // array of objects\n return users.map(u => u.name)\n}\n```\n\n---\n\n## Safety Markers\n\n### Unsafe Functions\n\nSkip validation for hot paths:\n\n```typescript\nfunction fastAdd(! a: 0, b: 0) { return a + b }\n```\n\nThe `!` marker after the function name skips input validation.\n\n### Safe Functions\n\nExplicit validation (for emphasis):\n\n```typescript\nfunction safeAdd(? a: 0, b: 0) { return a + b }\n```\n\n### Unsafe Blocks\n\nSkip validation for a block of code:\n\n```typescript\nunsafe {\n fastPath(data)\n anotherHotFunction(moreData)\n}\n```\n\n### Module Safety Directive\n\nSet the default validation level for an entire file:\n\n```typescript\nsafety none // No validation (metadata only)\nsafety inputs // Validate function inputs (default)\nsafety all // Validate everything (debug mode)\n```\n\n---\n\n## Type System\n\n### Type()\n\nDefine named types with predicates:\n\n```typescript\n// Simple type from example\nType Name 'Alice'\n\n// Type with description\nType User {\n description: 'a user object'\n example: { name: '', age: 0 }\n}\n\n// Type with predicate\nType PositiveNumber {\n description: 'a positive number'\n example: 1\n predicate(x) { return x > 0 }\n}\n```\n\nTypes can be used in function signatures:\n\n```typescript\nfunction greet(name: Name) -> '' {\n return `Hello, ${name}!`\n}\n```\n\n### Generic()\n\nRuntime-checkable generics:\n\n```typescript\nGeneric Box<T> {\n description: 'a boxed value'\n predicate(x, T) {\n return typeof x === 'object' && x !== null && 'value' in x && T(x.value)\n }\n}\n\n// With default type parameter\nGeneric Container<T, U = ''> {\n description: 'container with label'\n predicate(obj, T, U) {\n return T(obj.item) && U(obj.label)\n }\n}\n```\n\n#### Declaration Blocks (for TypeScript Consumers)\n\nGenerics can include an optional `declaration` block that specifies the\nTypeScript interface to emit in `.d.ts` output. This is metadata for TS\nconsumers — it has no effect on runtime behavior.\n\n```typescript\nGeneric BoxedProxy<T> {\n description: 'typed reactive proxy'\n predicate(x, T) {\n return typeof x === 'object' && 'value' in x && T(x.value)\n }\n declaration {\n value: T\n path: string\n observe(cb: (path: string) => void): void\n touch(): void\n }\n}\n```\n\nWhen emitting `.d.ts` via `tjs emit --dts`, this produces:\n\n```typescript\nexport interface BoxedProxy<T> {\n value: T\n path: string\n observe(cb: (path: string) => void): void\n touch(): void\n}\n```\n\nThe declaration content is raw TypeScript syntax — it's emitted verbatim\ninto the `.d.ts` file. This lets TJS libraries provide proper TypeScript\ninterfaces while keeping the TJS source as the single source of truth.\n\nWithout a `declaration` block, Generics emit an `any`-based factory stub\nthat provides basic IDE hints without false type errors.\n\n### Union()\n\nDiscriminated unions:\n\n```typescript\nconst Shape = Union('kind', {\n circle: { radius: 0 },\n rectangle: { width: 0, height: 0 }\n})\n\nfunction area(shape: Shape) -> 0 {\n if (shape.kind === 'circle') {\n return Math.PI * shape.radius ** 2\n }\n return shape.width * shape.height\n}\n```\n\n### Enum()\n\nString or numeric enums:\n\n```typescript\nconst Status = Enum(['pending', 'active', 'completed'])\nconst Priority = Enum({ low: 1, medium: 2, high: 3 })\n\nfunction setStatus(status: Status) {}\n```\n\n---\n\n## Structural Equality: Is / IsNot\n\nJavaScript's `==` is broken (type coercion). TJS provides structural equality:\n\n```typescript\n// Structural comparison - no coercion\n[1, 2] Is [1, 2] // true\n5 Is \"5\" // false (different types)\n{ a: 1 } Is { a: 1 } // true\n\n// Arrays compared element-by-element\n[1, [2, 3]] Is [1, [2, 3]] // true\n\n// Negation\n5 IsNot \"5\" // true\n```\n\n### Custom Equality\n\nObjects can define custom equality in two ways:\n\n**1. `[tjsEquals]` symbol protocol** (preferred for Proxies and advanced use):\n\n```typescript\nimport { tjsEquals } from 'tjs-lang/lang'\n\n// A proxy that delegates equality to its target\nconst target = { x: 1, y: 2 }\nconst proxy = new Proxy({\n [tjsEquals](other) { return target Is other }\n}, {})\n\nproxy == { x: 1, y: 2 } // true — delegates to target\n```\n\n**2. `.Equals` method** (simple, works on any object or class):\n\n```typescript\nclass Point {\n constructor(x: 0, y: 0) { this.x = x; this.y = y }\n Equals(other) { return this.x === other.x && this.y === other.y }\n}\n\nPoint(1, 2) Is Point(1, 2) // true (uses .Equals)\n```\n\n**Priority:** `[tjsEquals]` symbol > `.Equals` method > structural comparison.\n\nThe symbol is `Symbol.for('tjs.equals')`, so it works across realms. Access it\nvia `import { tjsEquals } from 'tjs-lang/lang'` or `__tjs.tjsEquals` at runtime.\n\n---\n\n## Classes\n\n### Callable Without `new`\n\nWith the `TjsClass` directive, classes declared in your file are wrapped\nso they can be called without `new`:\n\n```typescript\nTjsClass\n\nclass User {\n constructor(name: '') {\n this.name = name\n }\n}\n\n// Both work identically:\nconst u1 = User('Alice') // TJS way - clean\nconst u2 = new User('Alice') // Also works (linter warns)\n```\n\nThe wrapping uses a Proxy on the constructor that intercepts bare calls\nand forwards them to `Reflect.construct`. This means `User('Alice')`\nand `new User('Alice')` always produce the same result — an instance.\n\n**What gets wrapped:** Only `class` declarations in your `.tjs` file.\nSpecifically:\n\n- `class Foo { }` in a file with `TjsClass` → wrapped\n- Built-in globals (`Boolean`, `Number`, `String`, `Array`) → **never touched**\n- Old-style constructor functions (`function Foo() { }` with `Foo.prototype`) → **never touched**\n\n**Why not built-ins:** JavaScript's built-in constructors have dual\nbehavior — `Boolean(0)` returns the primitive `false` (type coercion),\nwhile `new Boolean(0)` returns a `Boolean` object wrapping `false`\n(which is truthy!). If TJS wrapped `Boolean`, then `Boolean(0)` would\nsilently become `new Boolean(0)` — a truthy object instead of `false`.\nThe same applies to `Number()`, `String()`, and `Array()`.\n\n**Why not old-style constructors:** If you're using `function` +\n`prototype` to build a class manually, you may intentionally want\n`Foo(x)` to behave differently from `new Foo(x)` — the same dual\nbehavior pattern as the built-ins. TJS respects this by only wrapping\nthe `class` keyword, where calling without `new` has no existing\nmeaning in JavaScript (it throws `TypeError`).\n\n### Private Fields\n\nUse `#` for private fields:\n\n```typescript\nclass Counter {\n #count = 0\n\n increment() {\n this.#count++\n }\n get value() {\n return this.#count\n }\n}\n```\n\nWhen converting from TypeScript, `private foo` becomes `#foo`.\n\n### Getters and Setters\n\nAsymmetric types are captured:\n\n```typescript\nclass Timestamp {\n #value\n\n constructor(initial: '' | 0 | null) {\n this.#value = initial === null ? new Date() : new Date(initial)\n }\n\n set value(v: '' | 0 | null) {\n this.#value = v === null ? new Date() : new Date(v)\n }\n\n get value() {\n return this.#value\n }\n}\n\nconst ts = Timestamp('2024-01-15')\nts.value = 0 // SET accepts: string | number | null\nts.value // GET returns: Date\n```\n\n---\n\n## Polymorphic Functions\n\nMultiple function declarations with the same name are automatically merged into a dispatcher that routes by argument count and type:\n\n```typescript\nfunction describe(value: 0) {\n return 'number: ' + value\n}\nfunction describe(value: '') {\n return 'string: ' + value\n}\nfunction describe(value: { name: '' }) {\n return 'object: ' + value.name\n}\n\ndescribe(42) // 'number: 42'\ndescribe('hello') // 'string: hello'\ndescribe({ name: 'world' }) // 'object: world'\ndescribe(true) // MonadicError: no matching overload\n```\n\n### Dispatch Order\n\n1. **Arity** first (number of arguments)\n2. **Type specificity** within same arity: `integer` > `number` > `any`; objects before primitives\n3. **Declaration order** as tiebreaker\n\n### Polymorphic Constructors\n\nClasses can have multiple constructor signatures. The first becomes the real JS constructor; additional variants become factory functions:\n\n```typescript\nTjsClass\n\nclass Point {\n constructor(x: 0.0, y: 0.0) {\n this.x = x\n this.y = y\n }\n constructor(coords: { x: 0.0; y: 0.0 }) {\n this.x = coords.x\n this.y = coords.y\n }\n}\n\nPoint(3, 4) // variant 1: two numbers\nPoint({ x: 10, y: 20 }) // variant 2: object\n```\n\nAll variants produce correct `instanceof` results.\n\n### Compile-Time Validation\n\nTJS catches these errors at transpile time:\n\n- **Ambiguous signatures**: Two variants with identical types at every position\n- **Rest parameters**: `...args` not supported in polymorphic functions\n- **Mixed async/sync**: All variants must agree\n\n---\n\n## Local Class Extensions\n\nAdd methods to built-in types without polluting prototypes:\n\n```typescript\nextend String {\n capitalize() {\n return this[0].toUpperCase() + this.slice(1)\n }\n words() {\n return this.split(/\\s+/)\n }\n}\n\n'hello world'.capitalize() // 'Hello world'\n'foo bar baz'.words() // ['foo', 'bar', 'baz']\n```\n\n### How It Works\n\nFor known-type receivers (literals, typed variables), calls are rewritten at transpile time to `.call()` — zero runtime overhead:\n\n```javascript\n// TJS source:\n'hello'.capitalize()\n\n// Generated JS:\n__ext_String.capitalize.call('hello')\n```\n\nFor unknown types, a runtime registry (`registerExtension` / `resolveExtension`) provides fallback dispatch.\n\n### Supported Types\n\nExtensions work on any type: `String`, `Number`, `Array`, `Boolean`, custom classes, and DOM classes like `HTMLElement`. Multiple `extend` blocks for the same type merge left-to-right (later declarations can override earlier methods).\n\n### Rules\n\n- Arrow functions are **not allowed** in extend blocks (they don't bind `this`)\n- Extensions are **file-local** — they don't leak across modules\n- Prototypes are **never modified** — `String.prototype.capitalize` remains `undefined`\n\n---\n\n## Runtime Features\n\n### `__tjs` Metadata\n\nEvery TJS function carries its type information:\n\n```typescript\nfunction createUser(input: { name: '', age: 0 }) -> { id: 0 } {\n return { id: 123 }\n}\n\nconsole.log(createUser.__tjs)\n// {\n// params: {\n// input: { type: { kind: 'object', shape: { name: 'string', age: 'number' } } }\n// },\n// returns: { kind: 'object', shape: { id: 'number' } }\n// }\n```\n\nThis enables:\n\n- Autocomplete from live objects\n- Runtime type validation\n- Automatic documentation generation\n\n### Monadic Errors\n\nType validation failures return `MonadicError` instances (extends `Error`),\nnot thrown exceptions:\n\n```typescript\nimport { isMonadicError } from 'tjs-lang/lang'\n\nconst result = createUser({ name: 123 }) // wrong type\n// MonadicError: Expected string for 'createUser.name', got number\n\nif (isMonadicError(result)) {\n console.log(result.message) // \"Expected string for 'createUser.name', got number\"\n console.log(result.path) // \"createUser.name\"\n console.log(result.expected) // \"string\"\n console.log(result.actual) // \"number\"\n}\n```\n\nNo try/catch gambling. The host survives invalid inputs.\n\nFor general-purpose error values (not type errors), use the `error()` helper\nwhich returns plain `{ $error: true, message }` objects checkable with `isError()`.\n\n### Inline Tests\n\nTests live next to code:\n\n```typescript\nfunction double(x: 0) -> 0 { return x * 2 }\n\ntest('doubles numbers') {\n expect(double(5)).toBe(10)\n expect(double(-3)).toBe(-6)\n}\n```\n\nTests are extracted at compile time and can be:\n\n- Run during transpilation\n- Stripped in production builds\n- Used for documentation generation\n\n### WASM Blocks\n\nDrop into WebAssembly for compute-heavy code:\n\n```typescript\nfunction vectorDot(a: [0], b: [0]) -> 0 {\n let sum = 0\n wasm {\n for (let i = 0; i < a.length; i++) {\n sum = sum + a[i] * b[i]\n }\n }\n return sum\n}\n```\n\nVariables are captured automatically. Falls back to JS if WASM unavailable.\n\n#### SIMD Intrinsics (f32x4)\n\nFor compute-heavy workloads, use f32x4 SIMD intrinsics to process 4 float32 values per instruction:\n\n```typescript\nconst scale = wasm (arr: Float32Array, len: 0, factor: 0.0) -> 0 {\n let s = f32x4_splat(factor)\n for (let i = 0; i < len; i += 4) {\n let off = i * 4\n let v = f32x4_load(arr, off)\n f32x4_store(arr, off, f32x4_mul(v, s))\n }\n} fallback {\n for (let i = 0; i < len; i++) arr[i] *= factor\n}\n```\n\nAvailable intrinsics:\n\n| Intrinsic | Description |\n| ----------------------------------- | ------------------------------------ |\n| `f32x4_load(ptr, byteOffset)` | Load 4 floats from memory into v128 |\n| `f32x4_store(ptr, byteOffset, vec)` | Store v128 as 4 floats to memory |\n| `f32x4_splat(scalar)` | Fill all 4 lanes with a scalar value |\n| `f32x4_extract_lane(vec, N)` | Extract float from lane 0-3 |\n| `f32x4_replace_lane(vec, N, val)` | Replace one lane, return new v128 |\n| `f32x4_add(a, b)` | Lane-wise addition |\n| `f32x4_sub(a, b)` | Lane-wise subtraction |\n| `f32x4_mul(a, b)` | Lane-wise multiplication |\n| `f32x4_div(a, b)` | Lane-wise division |\n| `f32x4_neg(v)` | Negate all lanes |\n| `f32x4_sqrt(v)` | Square root of all lanes |\n\nThis mirrors C/C++ SIMD intrinsics (`_mm_add_ps`, etc.) — explicit, predictable, no auto-vectorization magic.\n\n#### Zero-Copy Arrays: `wasmBuffer()`\n\nBy default, typed arrays passed to WASM blocks are copied into WASM memory before the call and copied back out after. For large arrays called frequently, this overhead can negate WASM's speed advantage.\n\n`wasmBuffer(Constructor, length)` allocates typed arrays directly in WASM linear memory. These arrays work like normal typed arrays from JavaScript, but when passed to a `wasm {}` block, they're zero-copy — the data is already there.\n\n```typescript\n// Allocate particle positions in WASM memory\nconst starX = wasmBuffer(Float32Array, 50000)\nconst starY = wasmBuffer(Float32Array, 50000)\n\n// Use from JS like normal arrays\nfor (let i = 0; i < 50000; i++) {\n starX[i] = (Math.random() - 0.5) * 2000\n starY[i] = (Math.random() - 0.5) * 2000\n}\n\n// Zero-copy SIMD processing\nfunction moveParticles(! xs: Float32Array, ys: Float32Array, len: 0, dx: 0.0, dy: 0.0) {\n wasm {\n let vdx = f32x4_splat(dx)\n let vdy = f32x4_splat(dy)\n for (let i = 0; i < len; i += 4) {\n let off = i * 4\n f32x4_store(xs, off, f32x4_add(f32x4_load(xs, off), vdx))\n f32x4_store(ys, off, f32x4_add(f32x4_load(ys, off), vdy))\n }\n } fallback {\n for (let i = 0; i < len; i++) { xs[i] += dx; ys[i] += dy }\n }\n}\n\n// After WASM runs, JS sees the mutations immediately\nmoveParticles(starX, starY, 50000, 1.0, 0.5)\nconsole.log(starX[0]) // updated in place, no copy\n```\n\nKey points:\n\n- Supported constructors: `Float32Array`, `Float64Array`, `Int32Array`, `Uint8Array`\n- Uses a bump allocator — allocations persist for program lifetime\n- All WASM blocks in a file share one 64MB memory\n- Regular typed arrays still work (copy in/out as before)\n- Use `!` (unsafe) on hot-path functions to skip runtime type checks\n\n---\n\n## Module System\n\nTJS preserves standard ES module semantics exactly. `import` and `export` statements pass through to the output unchanged — TJS does not have its own module resolver.\n\n### Importing .tjs Files\n\nIn **Bun** (with the TJS plugin from `bunfig.toml`):\n\n```typescript\n// .tjs files are transpiled automatically on import\nimport { processOrder } from './orders.tjs'\nimport { validateUser } from './users.ts' // TS files also work\n```\n\nIn the **browser playground**, local modules are resolved from the playground's module store. Relative imports are looked up by name:\n\n```typescript\nimport { formatDate } from './date-utils' // resolves from saved modules\n```\n\nIn **production builds** (`tjs emit`), TJS transpiles `.tjs` → `.js`. Your bundler (esbuild, Rollup, etc.) handles resolution of the output `.js` files normally.\n\n### Importing JS/TS Libraries\n\nTJS files can import any JavaScript or TypeScript library. The imported code runs without TJS validation — it's just normal JS. Add a TJS wrapper at the boundary if you want type safety:\n\n```typescript\nimport { rawGeocode } from 'legacy-geo-pkg'\n\n// Wrap at the boundary — rawGeocode is unchecked, geocode validates its output\nfunction geocode(addr: '') -> { lat: 0.0, lon: 0.0 } {\n return rawGeocode(addr)\n}\n```\n\n### CDN Imports\n\nURL imports work with any ESM CDN:\n\n```typescript\nimport lodash from 'https://esm.sh/lodash@4.17.21'\n```\n\n### Circular Dependencies\n\nTJS doesn't interfere with JS module loading. Circular imports work the same way as in standard ES modules — use lazy getters or late binding if you need to break cycles, exactly as you would in plain JS.\n\n### TypeScript Declaration Files (.d.ts)\n\nTJS can generate `.d.ts` files so TypeScript consumers can use TJS-authored libraries with autocomplete and tooltips:\n\n```bash\nbun src/cli/tjs.ts emit --dts src/lib.tjs -o dist/lib.js\n# Generates dist/lib.js + dist/lib.d.ts\n```\n\nFrom code:\n\n```typescript\nimport { tjs, generateDTS } from 'tjs-lang'\n\nconst result = tjs(source)\nconst dts = generateDTS(result, source)\n```\n\nFunctions get full type declarations. Classes, generics, and predicate-based types get `any`-based stubs that provide IDE hints (parameter names, object shapes) without generating false lint errors for types that TJS validates at runtime.\n\n---\n\n## TypeScript Compatibility\n\n### TS → TJS Converter\n\nConvert existing TypeScript:\n\n```bash\nbun src/cli/tjs.ts convert file.ts\n```\n\n```typescript\n// TypeScript\nfunction greet(name: string, age?: number): string { ... }\n\n// Converts to TJS\nfunction greet(name: '', age = 0) -> '' { ... }\n```\n\n### What Gets Converted\n\n| TypeScript | TJS |\n| -------------------------- | ----------------------- |\n| `name: string` | `name: ''` |\n| `age: number` | `age: 0.0` |\n| `flag: boolean` | `flag: false` |\n| `items: string[]` | `items: ['']` |\n| `age?: number` | `age: 0.0 \\| undefined` |\n| `private foo` | `#foo` |\n| `interface User` | `Type User` |\n| `type Status = 'a' \\| 'b'` | `Union(['a', 'b'])` |\n| `enum Color` | `Enum(...)` |\n\n> **Optional params:** TypeScript `x?: boolean` becomes TJS `x: false | undefined`.\n> This preserves the three-state semantics (`true` / `false` / `undefined`)\n> using a union type. The param is required but explicitly accepts `undefined`.\n\n---\n\n## Performance\n\n| Mode | Overhead | Use Case |\n| --------------- | --------- | ------------------------------- |\n| `safety none` | **1.0x** | Metadata only, no validation |\n| `safety inputs` | **~1.5x** | Production (single-arg objects) |\n| `(!) unsafe` | **1.0x** | Hot paths |\n| `wasm {}` | **<1.0x** | Compute-heavy code |\n\n### Why 1.5x, Not 25x\n\nMost validators interpret schemas at runtime (~25x overhead). TJS generates inline checks at transpile time:\n\n```typescript\n// Generated (JIT-friendly)\nif (\n typeof input !== 'object' ||\n input === null ||\n typeof input.name !== 'string' ||\n typeof input.age !== 'number'\n) {\n return { $error: true, message: 'Invalid input', path: 'fn.input' }\n}\n```\n\nNo schema interpretation. No object iteration. The JIT inlines these completely.\n\n---\n\n## Bare Assignments\n\nUppercase identifiers automatically get `const`:\n\n```typescript\nFoo = Type('test', 'example') // becomes: const Foo = Type(...)\nMyConfig = { debug: true } // becomes: const MyConfig = { ... }\n```\n\n---\n\n## Limitations\n\n### What TJS Doesn't Do\n\n- **No gradual typing** — types are all-or-nothing per function\n- **No complex type inference** — you provide examples, not constraints\n- **No type-level computation** — no conditional types, mapped types, etc.\n\n### What TJS Intentionally Avoids\n\n- Build steps beyond transpilation\n- External type checkers\n- Complex tooling configuration\n- Separation of types from runtime\n\n---\n\n## Troubleshooting\n\n### Common Transpilation Errors\n\n**\"Unexpected token\"** — Usually means TJS-specific syntax (`:` params, `->` returns, `Type`, `Generic`) wasn't recognized. Check:\n\n- Is the file being parsed as TJS (not plain JS)?\n- Are `Type`/`Generic`/`Union` declarations at the top level (not inside functions)?\n- Is the `->` return type before the function body `{`?\n\n**\"Type is not defined\" / \"Generic is not defined\"** — These become `const Name = Type(...)` / `const Name = Generic(...)` after preprocessing. If you see this at runtime, the TJS runtime (`createRuntime()`) wasn't installed, or the file wasn't transpiled through TJS.\n\n**Signature test failures** — TJS runs your function with its example values at transpile time. If the function fails with its own examples, transpilation reports an error. Fix the function or choose better examples:\n\n```typescript\n// BAD: example 0 causes division by zero\nfunction inverse(x: 0) -> 0.0 { return 1 / x }\n\n// GOOD: example 1 works\nfunction inverse(x: 1) -> 0.0 { return 1 / x }\n```\n\n**Monadic errors instead of exceptions** — TJS validation returns `MonadicError` objects (with `$error: true`), it doesn't throw. Check with `isMonadicError(result)`, not `try/catch`:\n\n```typescript\nimport { isMonadicError } from 'tjs-lang'\n\nconst result = myFunction(badInput)\nif (isMonadicError(result)) {\n console.log(result.message) // \"type mismatch: expected string, got number\"\n}\n```\n\n### Debugging Type Checks\n\nEvery transpiled function has `.__tjs` metadata you can inspect:\n\n```typescript\nconsole.log(myFunction.__tjs)\n// { params: { name: { type: { kind: 'string' }, required: true } },\n// returns: { kind: 'string' } }\n```\n\nThe transpiled JS is readable — look at the generated code to see exactly what checks run:\n\n```bash\nbun src/cli/tjs.ts emit myfile.tjs # see the generated JS\n```\n\n### When to Use `!` (Unsafe)\n\nMark functions unsafe when:\n\n- The data source is already validated (e.g., internal helper called only from a validated wrapper)\n- You're in a hot loop and profiling shows the checks matter\n- You're calling a function millions of times with known-good data\n\nDon't use `!` at system boundaries (API handlers, user input, external data).\n\n---\n\n## Learn More\n\n- [AJS Documentation](DOCS-AJS.md) — The agent runtime\n- [Builder's Manifesto](MANIFESTO-BUILDER.md) — Why TJS is fun\n- [Enterprise Guide](MANIFESTO-ENTERPRISE.md) — Why TJS is safe\n- [Technical Context](CONTEXT.md) — Architecture deep dive\n"
154
+ "text": "<!--{\"section\": \"tjs\", \"group\": \"docs\", \"order\": 0, \"navTitle\": \"Documentation\"}-->\n\n# TJS: Typed JavaScript\n\n_Types as Examples. Zero Build. Runtime Metadata._\n\n---\n\n## What is TJS?\n\nTJS is a typed superset of JavaScript where **types are concrete values**, not abstract annotations.\n\n```typescript\n// TypeScript: abstract type annotation\nfunction greet(name: string): string\n\n// TJS: concrete example value\nfunction greet(name: 'World') -> '' { return `Hello, ${name}!` }\n```\n\nThe example `'World'` tells TJS that `name` is a string. The example `''` tells TJS the return type is a string. Types are inferred from the examples you provide.\n\nTJS transpiles to JavaScript with embedded `__tjs` metadata, enabling runtime type checking, autocomplete from live objects, and documentation generation.\n\n---\n\n## TJS is JavaScript\n\nTJS is **purely additive**. It adds type annotations, runtime validation, and metadata on top of standard JavaScript. It does not replace, intercept, or modify any existing JavaScript semantics.\n\n**Everything you know about JavaScript still works:**\n\n- **Proxies** — fully supported. TJS never intercepts property access. `__tjs` metadata is a plain property assignment on the function object; it doesn't interfere with Proxy traps. The `[tjsEquals]` symbol protocol is specifically designed for Proxy-friendly custom equality.\n- **WeakMap, WeakSet, Map, Set** — all unchanged. TJS doesn't wrap or validate collection internals.\n- **Closures, Promises, async/await** — work identically to JS.\n- **Prototype chains** — preserved. `wrapClass()` uses a Proxy only on the class constructor (to allow calling without `new`), not on instances.\n- **Module semantics** — TJS preserves ES module `import`/`export` exactly. Lazy getters, circular dependencies, and re-exports work the same as in JS.\n- **`this` binding** — unchanged. Arrow functions, `.bind()`, `.call()`, `.apply()` all work normally.\n- **Regular expressions, JSON, Math, Date** — all standard built-ins are available and unmodified (though `TjsDate` directive can optionally ban `Date` in favor of safer alternatives).\n\n**What TJS adds (and when):**\n\n| Addition | When | Overhead |\n| ---------------------- | ----------------------------------------- | ----------------------------- |\n| Parameter validation | Function entry (unless `!` unsafe) | ~1.5x on that function |\n| Return type validation | Function exit (only with `safety all`) | ~1.5x on that function |\n| `__tjs` metadata | Transpile time | Zero runtime cost |\n| `wrapClass` Proxy | Class declaration (with `TjsClass`) | One-time, on constructor only |\n| Structural equality | Only when `==`/`!=` used with `TjsEquals` | Per-comparison |\n\nIf TJS doesn't understand something in your code, it passes it through unchanged. There is no \"TJS runtime\" that interposes between your code and the JS engine — just the inline checks you can see in the transpiled output.\n\n---\n\n## The Compiler\n\nTJS compiles in the browser. No webpack, no node_modules, no build server.\n\n```typescript\nimport { tjs } from 'tjs-lang'\n\nconst code = tjs`\n function add(a: 0, b: 0) -> 0 {\n return a + b\n }\n`\n\n// Returns transpiled JavaScript with __tjs metadata\n```\n\nYou can also use the CLI:\n\n```bash\nbun src/cli/tjs.ts check file.tjs # Parse and type check\nbun src/cli/tjs.ts run file.tjs # Transpile and execute\nbun src/cli/tjs.ts emit file.tjs # Output transpiled JS\nbun src/cli/tjs.ts types file.tjs # Output type metadata\n```\n\n---\n\n## Syntax\n\n### Parameter Types (Colon Syntax)\n\n> **Not TypeScript.** TJS colon syntax looks like TypeScript but has different\n> semantics. The value after `:` is a **concrete example**, not a type name.\n> Write `name: 'Alice'` (example value), not `name: string` (type name).\n> TJS infers the type from the example: `'Alice'` → string, `0` → integer,\n> `true` → boolean.\n\nRequired parameters use colon syntax with an example value:\n\n```typescript\nfunction greet(name: 'Alice') {} // name is required, type: string\nfunction calculate(value: 0) {} // value is required, type: integer\nfunction measure(rate: 0.0) {} // rate is required, type: number (float)\nfunction count(n: +0) {} // n is required, type: non-negative integer\nfunction toggle(flag: true) {} // flag is required, type: boolean\n```\n\n### Numeric Types\n\nTJS distinguishes three numeric types using valid JavaScript syntax:\n\n```typescript\nfunction process(\n rate: 3.14, // number (float) -- has a decimal point\n count: 42, // integer -- whole number, no decimal\n index: +0 // non-negative integer -- prefixed with +\n) {}\n```\n\n| You Write | Type Inferred | Runtime Validation |\n| --------- | ---------------------- | ------------------------------- |\n| `3.14` | `number` (float) | `typeof x === 'number'` |\n| `0.0` | `number` (float) | `typeof x === 'number'` |\n| `42` | `integer` | `Number.isInteger(x)` |\n| `0` | `integer` | `Number.isInteger(x)` |\n| `+20` | `non-negative integer` | `Number.isInteger(x) && x >= 0` |\n| `+0` | `non-negative integer` | `Number.isInteger(x) && x >= 0` |\n| `-5` | `integer` | `Number.isInteger(x)` |\n| `-3.5` | `number` (float) | `typeof x === 'number'` |\n\nAll of these are valid JavaScript expressions. TJS reads the syntax more\ncarefully to give you finer-grained type checking than JS or TypeScript\nprovide natively.\n\n### Optional Parameters (Default Values)\n\nOptional parameters use `=` with a default value:\n\n```typescript\nfunction greet(name = 'World') {} // name is optional, defaults to 'World'\nfunction calculate(value = 0) {} // value is optional, defaults to 0 (integer)\n```\n\n### TypeScript-Style Optional (`?:`)\n\nTJS supports `?:` for compatibility, but consider it a migration aid rather than idiomatic TJS:\n\n```typescript\nfunction greet(name?: '') {} // same as name = ''\n```\n\n**Why `?:` is an antipattern.** In TypeScript, `?:` creates a three-state parameter\n(`value | undefined | missing`) that forces every function body to handle the absent case:\n\n```typescript\n// TypeScript — every caller and callee must reason about undefined\nfunction greet(name?: string) {\n const safeName = name ?? 'World' // defensive check required\n return `Hello, ${safeName}!`\n}\n```\n\nTJS offers two better alternatives:\n\n**1. Safe defaults** — the parameter always has a value, no branching needed:\n\n```typescript\nfunction greet(name = 'World') {\n return `Hello, ${name}!` // name is always a string\n}\n```\n\n**2. Polymorphic functions** — separate signatures for separate behavior:\n\n```typescript\nfunction greet() {\n return 'Hello, World!'\n}\nfunction greet(name: '') {\n return `Hello, ${name}!`\n}\n```\n\nBoth approaches eliminate the `undefined` state entirely. The function body\nnever needs a null check because the type system guarantees a valid value\nat every call site. This is simpler to write, simpler to read, and produces\ntighter runtime validation.\n\n### Object Parameters\n\nObject shapes are defined by example:\n\n```typescript\nfunction createUser(user: { name: ''; age: 0 }) {}\n// user must be an object with string name and number age\n```\n\n### Nullable Types\n\nUse `|` for union with null:\n\n```typescript\nfunction find(id: 0 | null) {} // number or null\n```\n\n### Rest Parameters\n\nRest params use `:` with an array example. The annotation is stripped from\nthe JS output (JS doesn't allow defaults on rest params) but captured in\n`__tjs` metadata:\n\n```typescript\nfunction sum(...nums: [1, 2, 3]) -> 6 {\n return nums.reduce((a = 0, b: 0) => a + b, 0)\n}\n\nfunction mean(...values: [1.0, 2.0, 3.0, 2.0]) -> 2.0 {\n return values.length\n ? values.reduce((sum = 0.0, x: 1.0) => sum + x) / values.length\n : 0.0\n}\n```\n\nSignature tests work with rest params — the example array elements are\nspread as individual arguments. `mean(1.0, 2.0, 3.0, 2.0)` is called\nand the result is checked against the `-> 2.0` expected return using\nexact value comparison (deepEqual).\n\nThe array example tells TJS the element type. `[0]` means \"array of\nintegers\", `[1.0, 2.0]` means \"array of numbers (floats)\".\n\n**Heterogeneous arrays** infer a union item type:\n\n```typescript\nfunction log(...args: ['info', 42, true]) {}\n// args type: array<string | integer | boolean>\n```\n\n### Return Types (Arrow Syntax)\n\nReturn types use `->`:\n\n```typescript\nfunction add(a: 0, b: 0) -> 0 {\n return a + b\n}\n\nfunction getUser(id: 0) -> { name: '', age: 0 } {\n return { name: 'Alice', age: 30 }\n}\n```\n\n### Array Types\n\nArrays use bracket syntax with an example element:\n\n```typescript\nfunction sum(numbers: [0]) -> 0 { // array of numbers\n return numbers.reduce((a, b) => a + b, 0)\n}\n\nfunction names(users: [{ name: '' }]) { // array of objects\n return users.map(u => u.name)\n}\n```\n\n---\n\n## Safety Markers\n\n### Unsafe Functions\n\nSkip validation for hot paths:\n\n```typescript\nfunction fastAdd(! a: 0, b: 0) { return a + b }\n```\n\nThe `!` marker after the function name skips input validation.\n\n### Safe Functions\n\nExplicit validation (for emphasis):\n\n```typescript\nfunction safeAdd(? a: 0, b: 0) { return a + b }\n```\n\n### Unsafe Blocks\n\nSkip validation for a block of code:\n\n```typescript\nunsafe {\n fastPath(data)\n anotherHotFunction(moreData)\n}\n```\n\n### Module Safety Directive\n\nSet the default validation level for an entire file:\n\n```typescript\nsafety none // No validation (metadata only)\nsafety inputs // Validate function inputs (default)\nsafety all // Validate everything (debug mode)\n```\n\n---\n\n## Type System\n\n### Type()\n\nDefine named types with predicates:\n\n```typescript\n// Simple type from example\nType Name 'Alice'\n\n// Type with description\nType User {\n description: 'a user object'\n example: { name: '', age: 0 }\n}\n\n// Type with predicate\nType PositiveNumber {\n description: 'a positive number'\n example: 1\n predicate(x) { return x > 0 }\n}\n```\n\nTypes can be used in function signatures:\n\n```typescript\nfunction greet(name: Name) -> '' {\n return `Hello, ${name}!`\n}\n```\n\n### Generic()\n\nRuntime-checkable generics:\n\n```typescript\nGeneric Box<T> {\n description: 'a boxed value'\n predicate(x, T) {\n return typeof x === 'object' && x !== null && 'value' in x && T(x.value)\n }\n}\n\n// With default type parameter\nGeneric Container<T, U = ''> {\n description: 'container with label'\n predicate(obj, T, U) {\n return T(obj.item) && U(obj.label)\n }\n}\n```\n\n#### Declaration Blocks (for TypeScript Consumers)\n\nGenerics can include an optional `declaration` block that specifies the\nTypeScript interface to emit in `.d.ts` output. This is metadata for TS\nconsumers — it has no effect on runtime behavior.\n\n```typescript\nGeneric BoxedProxy<T> {\n description: 'typed reactive proxy'\n predicate(x, T) {\n return typeof x === 'object' && 'value' in x && T(x.value)\n }\n declaration {\n value: T\n path: string\n observe(cb: (path: string) => void): void\n touch(): void\n }\n}\n```\n\nWhen emitting `.d.ts` via `tjs emit --dts`, this produces:\n\n```typescript\nexport interface BoxedProxy<T> {\n value: T\n path: string\n observe(cb: (path: string) => void): void\n touch(): void\n}\n```\n\nThe declaration content is raw TypeScript syntax — it's emitted verbatim\ninto the `.d.ts` file. This lets TJS libraries provide proper TypeScript\ninterfaces while keeping the TJS source as the single source of truth.\n\nWithout a `declaration` block, Generics emit an `any`-based factory stub\nthat provides basic IDE hints without false type errors.\n\n### Union()\n\nDiscriminated unions:\n\n```typescript\nconst Shape = Union('kind', {\n circle: { radius: 0 },\n rectangle: { width: 0, height: 0 }\n})\n\nfunction area(shape: Shape) -> 0 {\n if (shape.kind === 'circle') {\n return Math.PI * shape.radius ** 2\n }\n return shape.width * shape.height\n}\n```\n\n### Enum()\n\nString or numeric enums:\n\n```typescript\nconst Status = Enum(['pending', 'active', 'completed'])\nconst Priority = Enum({ low: 1, medium: 2, high: 3 })\n\nfunction setStatus(status: Status) {}\n```\n\n---\n\n## Structural Equality: Is / IsNot\n\nJavaScript's `==` is broken (type coercion). TJS provides structural equality:\n\n```typescript\n// Structural comparison - no coercion\n[1, 2] Is [1, 2] // true\n5 Is \"5\" // false (different types)\n{ a: 1 } Is { a: 1 } // true\n\n// Arrays compared element-by-element\n[1, [2, 3]] Is [1, [2, 3]] // true\n\n// Negation\n5 IsNot \"5\" // true\n```\n\n### Custom Equality\n\nObjects can define custom equality in two ways:\n\n**1. `[tjsEquals]` symbol protocol** (preferred for Proxies and advanced use):\n\n```typescript\nimport { tjsEquals } from 'tjs-lang/lang'\n\n// A proxy that delegates equality to its target\nconst target = { x: 1, y: 2 }\nconst proxy = new Proxy({\n [tjsEquals](other) { return target Is other }\n}, {})\n\nproxy == { x: 1, y: 2 } // true — delegates to target\n```\n\n**2. `.Equals` method** (simple, works on any object or class):\n\n```typescript\nclass Point {\n constructor(x: 0, y: 0) { this.x = x; this.y = y }\n Equals(other) { return this.x === other.x && this.y === other.y }\n}\n\nPoint(1, 2) Is Point(1, 2) // true (uses .Equals)\n```\n\n**Priority:** `[tjsEquals]` symbol > `.Equals` method > structural comparison.\n\nThe symbol is `Symbol.for('tjs.equals')`, so it works across realms. Access it\nvia `import { tjsEquals } from 'tjs-lang/lang'` or `__tjs.tjsEquals` at runtime.\n\n---\n\n## Classes\n\n### Callable Without `new`\n\nWith the `TjsClass` directive, classes declared in your file are wrapped\nso they can be called without `new`:\n\n```typescript\nTjsClass\n\nclass User {\n constructor(name: '') {\n this.name = name\n }\n}\n\n// Both work identically:\nconst u1 = User('Alice') // TJS way - clean\nconst u2 = new User('Alice') // Also works (linter warns)\n```\n\nThe wrapping uses a Proxy on the constructor that intercepts bare calls\nand forwards them to `Reflect.construct`. This means `User('Alice')`\nand `new User('Alice')` always produce the same result — an instance.\n\n**What gets wrapped:** Only `class` declarations in your `.tjs` file.\nSpecifically:\n\n- `class Foo { }` in a file with `TjsClass` → wrapped\n- Built-in globals (`Boolean`, `Number`, `String`, `Array`) → **never touched**\n- Old-style constructor functions (`function Foo() { }` with `Foo.prototype`) → **never touched**\n\n**Why not built-ins:** JavaScript's built-in constructors have dual\nbehavior — `Boolean(0)` returns the primitive `false` (type coercion),\nwhile `new Boolean(0)` returns a `Boolean` object wrapping `false`\n(which is truthy!). If TJS wrapped `Boolean`, then `Boolean(0)` would\nsilently become `new Boolean(0)` — a truthy object instead of `false`.\nThe same applies to `Number()`, `String()`, and `Array()`.\n\n**Why not old-style constructors:** If you're using `function` +\n`prototype` to build a class manually, you may intentionally want\n`Foo(x)` to behave differently from `new Foo(x)` — the same dual\nbehavior pattern as the built-ins. TJS respects this by only wrapping\nthe `class` keyword, where calling without `new` has no existing\nmeaning in JavaScript (it throws `TypeError`).\n\n### Private Fields\n\nUse `#` for private fields:\n\n```typescript\nclass Counter {\n #count = 0\n\n increment() {\n this.#count++\n }\n get value() {\n return this.#count\n }\n}\n```\n\nWhen converting from TypeScript, `private foo` becomes `#foo`.\n\n### Getters and Setters\n\nAsymmetric types are captured:\n\n```typescript\nclass Timestamp {\n #value\n\n constructor(initial: '' | 0 | null) {\n this.#value = initial === null ? new Date() : new Date(initial)\n }\n\n set value(v: '' | 0 | null) {\n this.#value = v === null ? new Date() : new Date(v)\n }\n\n get value() {\n return this.#value\n }\n}\n\nconst ts = Timestamp('2024-01-15')\nts.value = 0 // SET accepts: string | number | null\nts.value // GET returns: Date\n```\n\n---\n\n## Polymorphic Functions\n\nMultiple function declarations with the same name are automatically merged into a dispatcher that routes by argument count and type:\n\n```typescript\nfunction describe(value: 0) {\n return 'number: ' + value\n}\nfunction describe(value: '') {\n return 'string: ' + value\n}\nfunction describe(value: { name: '' }) {\n return 'object: ' + value.name\n}\n\ndescribe(42) // 'number: 42'\ndescribe('hello') // 'string: hello'\ndescribe({ name: 'world' }) // 'object: world'\ndescribe(true) // MonadicError: no matching overload\n```\n\n### Dispatch Order\n\n1. **Arity** first (number of arguments)\n2. **Type specificity** within same arity: `integer` > `number` > `any`; objects before primitives\n3. **Declaration order** as tiebreaker\n\n### Polymorphic Constructors\n\nClasses can have multiple constructor signatures. The first becomes the real JS constructor; additional variants become factory functions:\n\n```typescript\nTjsClass\n\nclass Point {\n constructor(x: 0.0, y: 0.0) {\n this.x = x\n this.y = y\n }\n constructor(coords: { x: 0.0; y: 0.0 }) {\n this.x = coords.x\n this.y = coords.y\n }\n}\n\nPoint(3, 4) // variant 1: two numbers\nPoint({ x: 10, y: 20 }) // variant 2: object\n```\n\nAll variants produce correct `instanceof` results.\n\n### Compile-Time Validation\n\nTJS catches these errors at transpile time:\n\n- **Ambiguous signatures**: Two variants with identical types at every position\n- **Rest parameters**: `...args` not supported in polymorphic functions\n- **Mixed async/sync**: All variants must agree\n\n---\n\n## Local Class Extensions\n\nAdd methods to built-in types without polluting prototypes:\n\n```typescript\nextend String {\n capitalize() {\n return this[0].toUpperCase() + this.slice(1)\n }\n words() {\n return this.split(/\\s+/)\n }\n}\n\n'hello world'.capitalize() // 'Hello world'\n'foo bar baz'.words() // ['foo', 'bar', 'baz']\n```\n\n### How It Works\n\nFor known-type receivers (literals, typed variables), calls are rewritten at transpile time to `.call()` — zero runtime overhead:\n\n```javascript\n// TJS source:\n'hello'.capitalize()\n\n// Generated JS:\n__ext_String.capitalize.call('hello')\n```\n\nFor unknown types, a runtime registry (`registerExtension` / `resolveExtension`) provides fallback dispatch.\n\n### Supported Types\n\nExtensions work on any type: `String`, `Number`, `Array`, `Boolean`, custom classes, and DOM classes like `HTMLElement`. Multiple `extend` blocks for the same type merge left-to-right (later declarations can override earlier methods).\n\n### Rules\n\n- Arrow functions are **not allowed** in extend blocks (they don't bind `this`)\n- Extensions are **file-local** — they don't leak across modules\n- Prototypes are **never modified** — `String.prototype.capitalize` remains `undefined`\n\n---\n\n## Runtime Features\n\n### `__tjs` Metadata\n\nEvery TJS function carries its type information:\n\n```typescript\nfunction createUser(input: { name: '', age: 0 }) -> { id: 0 } {\n return { id: 123 }\n}\n\nconsole.log(createUser.__tjs)\n// {\n// params: {\n// input: { type: { kind: 'object', shape: { name: 'string', age: 'number' } } }\n// },\n// returns: { kind: 'object', shape: { id: 'number' } }\n// }\n```\n\nThis enables:\n\n- Autocomplete from live objects\n- Runtime type validation\n- Automatic documentation generation\n\n### Monadic Errors\n\nType validation failures return `MonadicError` instances (extends `Error`),\nnot thrown exceptions:\n\n```typescript\nimport { isMonadicError } from 'tjs-lang/lang'\n\nconst result = createUser({ name: 123 }) // wrong type\n// MonadicError: Expected string for 'createUser.name', got number\n\nif (isMonadicError(result)) {\n console.log(result.message) // \"Expected string for 'createUser.name', got number\"\n console.log(result.path) // \"createUser.name\"\n console.log(result.expected) // \"string\"\n console.log(result.actual) // \"number\"\n}\n```\n\nNo try/catch gambling. The host survives invalid inputs.\n\nFor general-purpose error values (not type errors), use the `error()` helper\nwhich returns plain `{ $error: true, message }` objects checkable with `isError()`.\n\n### Inline Tests\n\nTests live next to code:\n\n```typescript\nfunction double(x: 0) -> 0 { return x * 2 }\n\ntest('doubles numbers') {\n expect(double(5)).toBe(10)\n expect(double(-3)).toBe(-6)\n}\n```\n\nTests are extracted at compile time and can be:\n\n- Run during transpilation\n- Stripped in production builds\n- Used for documentation generation\n\n### WASM Blocks\n\nDrop into WebAssembly for compute-heavy code:\n\n```typescript\nfunction vectorDot(a: [0], b: [0]) -> 0 {\n let sum = 0\n wasm {\n for (let i = 0; i < a.length; i++) {\n sum = sum + a[i] * b[i]\n }\n }\n return sum\n}\n```\n\nVariables are captured automatically. Falls back to JS if WASM unavailable.\n\n#### SIMD Intrinsics (f32x4)\n\nFor compute-heavy workloads, use f32x4 SIMD intrinsics to process 4 float32 values per instruction:\n\n```typescript\nconst scale = wasm (arr: Float32Array, len: 0, factor: 0.0) -> 0 {\n let s = f32x4_splat(factor)\n for (let i = 0; i < len; i += 4) {\n let off = i * 4\n let v = f32x4_load(arr, off)\n f32x4_store(arr, off, f32x4_mul(v, s))\n }\n} fallback {\n for (let i = 0; i < len; i++) arr[i] *= factor\n}\n```\n\nAvailable intrinsics:\n\n| Intrinsic | Description |\n| ----------------------------------- | ------------------------------------ |\n| `f32x4_load(ptr, byteOffset)` | Load 4 floats from memory into v128 |\n| `f32x4_store(ptr, byteOffset, vec)` | Store v128 as 4 floats to memory |\n| `f32x4_splat(scalar)` | Fill all 4 lanes with a scalar value |\n| `f32x4_extract_lane(vec, N)` | Extract float from lane 0-3 |\n| `f32x4_replace_lane(vec, N, val)` | Replace one lane, return new v128 |\n| `f32x4_add(a, b)` | Lane-wise addition |\n| `f32x4_sub(a, b)` | Lane-wise subtraction |\n| `f32x4_mul(a, b)` | Lane-wise multiplication |\n| `f32x4_div(a, b)` | Lane-wise division |\n| `f32x4_neg(v)` | Negate all lanes |\n| `f32x4_sqrt(v)` | Square root of all lanes |\n\nThis mirrors C/C++ SIMD intrinsics (`_mm_add_ps`, etc.) — explicit, predictable, no auto-vectorization magic.\n\n#### Zero-Copy Arrays: `wasmBuffer()`\n\nBy default, typed arrays passed to WASM blocks are copied into WASM memory before the call and copied back out after. For large arrays called frequently, this overhead can negate WASM's speed advantage.\n\n`wasmBuffer(Constructor, length)` allocates typed arrays directly in WASM linear memory. These arrays work like normal typed arrays from JavaScript, but when passed to a `wasm {}` block, they're zero-copy — the data is already there.\n\n```typescript\n// Allocate particle positions in WASM memory\nconst starX = wasmBuffer(Float32Array, 50000)\nconst starY = wasmBuffer(Float32Array, 50000)\n\n// Use from JS like normal arrays\nfor (let i = 0; i < 50000; i++) {\n starX[i] = (Math.random() - 0.5) * 2000\n starY[i] = (Math.random() - 0.5) * 2000\n}\n\n// Zero-copy SIMD processing\nfunction moveParticles(! xs: Float32Array, ys: Float32Array, len: 0, dx: 0.0, dy: 0.0) {\n wasm {\n let vdx = f32x4_splat(dx)\n let vdy = f32x4_splat(dy)\n for (let i = 0; i < len; i += 4) {\n let off = i * 4\n f32x4_store(xs, off, f32x4_add(f32x4_load(xs, off), vdx))\n f32x4_store(ys, off, f32x4_add(f32x4_load(ys, off), vdy))\n }\n } fallback {\n for (let i = 0; i < len; i++) { xs[i] += dx; ys[i] += dy }\n }\n}\n\n// After WASM runs, JS sees the mutations immediately\nmoveParticles(starX, starY, 50000, 1.0, 0.5)\nconsole.log(starX[0]) // updated in place, no copy\n```\n\nKey points:\n\n- Supported constructors: `Float32Array`, `Float64Array`, `Int32Array`, `Uint8Array`\n- Uses a bump allocator — allocations persist for program lifetime\n- All WASM blocks in a file share one 64MB memory\n- Regular typed arrays still work (copy in/out as before)\n- Use `!` (unsafe) on hot-path functions to skip runtime type checks\n\n---\n\n## Module System\n\nTJS preserves standard ES module semantics exactly. `import` and `export` statements pass through to the output unchanged — TJS does not have its own module resolver.\n\n### Importing .tjs Files\n\nIn **Bun** (with the TJS plugin from `bunfig.toml`):\n\n```typescript\n// .tjs files are transpiled automatically on import\nimport { processOrder } from './orders.tjs'\nimport { validateUser } from './users.ts' // TS files also work\n```\n\nIn the **browser playground**, local modules are resolved from the playground's module store. Relative imports are looked up by name:\n\n```typescript\nimport { formatDate } from './date-utils' // resolves from saved modules\n```\n\nIn **production builds** (`tjs emit`), TJS transpiles `.tjs` → `.js`. Your bundler (esbuild, Rollup, etc.) handles resolution of the output `.js` files normally.\n\n### Importing JS/TS Libraries\n\nTJS files can import any JavaScript or TypeScript library. The imported code runs without TJS validation — it's just normal JS. Add a TJS wrapper at the boundary if you want type safety:\n\n```typescript\nimport { rawGeocode } from 'legacy-geo-pkg'\n\n// Wrap at the boundary — rawGeocode is unchecked, geocode validates its output\nfunction geocode(addr: '') -> { lat: 0.0, lon: 0.0 } {\n return rawGeocode(addr)\n}\n```\n\n### CDN Imports\n\nURL imports work with any ESM CDN:\n\n```typescript\nimport lodash from 'https://esm.sh/lodash@4.17.21'\n```\n\n### Circular Dependencies\n\nTJS doesn't interfere with JS module loading. Circular imports work the same way as in standard ES modules — use lazy getters or late binding if you need to break cycles, exactly as you would in plain JS.\n\n### TypeScript Declaration Files (.d.ts)\n\nTJS can generate `.d.ts` files so TypeScript consumers can use TJS-authored libraries with autocomplete and tooltips:\n\n```bash\nbun src/cli/tjs.ts emit --dts src/lib.tjs -o dist/lib.js\n# Generates dist/lib.js + dist/lib.d.ts\n```\n\nFrom code:\n\n```typescript\nimport { tjs, generateDTS } from 'tjs-lang'\n\nconst result = tjs(source)\nconst dts = generateDTS(result, source)\n```\n\nFunctions get full type declarations. Classes, generics, and predicate-based types get `any`-based stubs that provide IDE hints (parameter names, object shapes) without generating false lint errors for types that TJS validates at runtime.\n\n---\n\n## TypeScript Compatibility\n\n### TS → TJS Converter\n\nConvert existing TypeScript:\n\n```bash\nbun src/cli/tjs.ts convert file.ts\n```\n\n```typescript\n// TypeScript\nfunction greet(name: string, age?: number): string { ... }\n\n// Converts to TJS\nfunction greet(name: '', age = 0) -> '' { ... }\n```\n\n### What Gets Converted\n\n| TypeScript | TJS |\n| -------------------------- | ----------------------- |\n| `name: string` | `name: ''` |\n| `age: number` | `age: 0.0` |\n| `flag: boolean` | `flag: false` |\n| `items: string[]` | `items: ['']` |\n| `age?: number` | `age: 0.0 \\| undefined` |\n| `private foo` | `#foo` |\n| `interface User` | `Type User` |\n| `type Status = 'a' \\| 'b'` | `Union(['a', 'b'])` |\n| `enum Color` | `Enum(...)` |\n\n> **Optional params:** TypeScript `x?: boolean` becomes TJS `x: false | undefined`.\n> This preserves the three-state semantics (`true` / `false` / `undefined`)\n> using a union type. The param is required but explicitly accepts `undefined`.\n\n---\n\n## Performance\n\n| Mode | Overhead | Use Case |\n| --------------- | --------- | ------------------------------- |\n| `safety none` | **1.0x** | Metadata only, no validation |\n| `safety inputs` | **~1.5x** | Production (single-arg objects) |\n| `(!) unsafe` | **1.0x** | Hot paths |\n| `wasm {}` | **<1.0x** | Compute-heavy code |\n\n### Why 1.5x, Not 25x\n\nMost validators interpret schemas at runtime (~25x overhead). TJS generates inline checks at transpile time:\n\n```typescript\n// Generated (JIT-friendly)\nif (\n typeof input !== 'object' ||\n input === null ||\n typeof input.name !== 'string' ||\n typeof input.age !== 'number'\n) {\n return { $error: true, message: 'Invalid input', path: 'fn.input' }\n}\n```\n\nNo schema interpretation. No object iteration. The JIT inlines these completely.\n\n---\n\n## Bare Assignments\n\nUppercase identifiers automatically get `const`:\n\n```typescript\nFoo = Type('test', 'example') // becomes: const Foo = Type(...)\nMyConfig = { debug: true } // becomes: const MyConfig = { ... }\n```\n\n---\n\n## Limitations\n\n### What TJS Doesn't Do\n\n- **No gradual typing** — types are all-or-nothing per function\n- **No complex type inference** — you provide examples, not constraints\n- **No type-level computation** — no conditional types, mapped types, etc.\n\n### What TJS Intentionally Avoids\n\n- Build steps beyond transpilation\n- External type checkers\n- Complex tooling configuration\n- Separation of types from runtime\n\n---\n\n## Troubleshooting\n\n### Common Transpilation Errors\n\n**\"Unexpected token\"** — Usually means TJS-specific syntax (`:` params, `->` returns, `Type`, `Generic`) wasn't recognized. Check:\n\n- Is the file being parsed as TJS (not plain JS)?\n- Are `Type`/`Generic`/`Union` declarations at the top level (not inside functions)?\n- Is the `->` return type before the function body `{`?\n\n**\"Type is not defined\" / \"Generic is not defined\"** — These become `const Name = Type(...)` / `const Name = Generic(...)` after preprocessing. If you see this at runtime, the TJS runtime (`createRuntime()`) wasn't installed, or the file wasn't transpiled through TJS.\n\n**Signature test failures** — TJS runs your function with its example values at transpile time. If the function fails with its own examples, transpilation reports an error. Fix the function or choose better examples:\n\n```typescript\n// BAD: example 0 causes division by zero\nfunction inverse(x: 0) -> 0.0 { return 1 / x }\n\n// GOOD: example 1 works\nfunction inverse(x: 1) -> 0.0 { return 1 / x }\n```\n\n**Monadic errors instead of exceptions** — TJS validation returns `MonadicError` objects (with `$error: true`), it doesn't throw. Check with `isMonadicError(result)`, not `try/catch`:\n\n```typescript\nimport { isMonadicError } from 'tjs-lang'\n\nconst result = myFunction(badInput)\nif (isMonadicError(result)) {\n console.log(result.message) // \"type mismatch: expected string, got number\"\n}\n```\n\n### Debugging Type Checks\n\nEvery transpiled function has `.__tjs` metadata you can inspect:\n\n```typescript\nconsole.log(myFunction.__tjs)\n// { params: { name: { type: { kind: 'string' }, required: true } },\n// returns: { kind: 'string' } }\n```\n\nThe transpiled JS is readable — look at the generated code to see exactly what checks run:\n\n```bash\nbun src/cli/tjs.ts emit myfile.tjs # see the generated JS\n```\n\n### When to Use `!` (Unsafe)\n\nMark functions unsafe when:\n\n- The data source is already validated (e.g., internal helper called only from a validated wrapper)\n- You're in a hot loop and profiling shows the checks matter\n- You're calling a function millions of times with known-good data\n\nDon't use `!` at system boundaries (API handlers, user input, external data).\n\n---\n\n## Learn More\n\n- [AJS Documentation](DOCS-AJS.md) — The agent runtime\n- [Builder's Manifesto](MANIFESTO-BUILDER.md) — Why TJS is fun\n- [Enterprise Guide](MANIFESTO-ENTERPRISE.md) — Why TJS is safe\n- [Technical Context](CONTEXT.md) — Architecture deep dive\n"
155
155
  },
156
156
  {
157
157
  "title": "Starfield",
@@ -173,7 +173,7 @@
173
173
  "type": "example",
174
174
  "group": "featured",
175
175
  "order": 0,
176
- "code": "// ═══════════════════════════════════════════════════════════\n// 1. SAFETY DIRECTIVE & TJS MODES\n// These must appear before any other code.\n// ═══════════════════════════════════════════════════════════\n\nsafety inputs\n\nTjsEquals\nTjsClass\n\n/*#\n# TJS Grammar Reference\n\nA runnable reference for TJS syntax. Each section demonstrates a\nfeature with a test proving it works.\n\n## Quick Index\n| Feature | Section |\n|---------|---------|\n| Safety & modes | `safety`, `TjsEquals`, `TjsClass` |\n| Parameters | Colon `:`, optional `=`, destructured `{}` |\n| Numeric narrowing | `42` int, `3.14` float, `+0` non-negative |\n| Return types | `->`, `-?`, `-!` |\n| Safety markers | `(! ...)` unsafe, `(? ...)` safe |\n| Type/Generic/Enum/Union | See above (requires full runtime) |\n| Bare assignments | `Uppercase = ...` |\n| Classes | Callable without `new` |\n| Polymorphic functions | Same name, different signatures |\n| Polymorphic constructors | Multiple `constructor()` |\n| Local extensions | `extend String { ... }` |\n| Equality | `==` structural, `===` identity, `Is`/`IsNot` |\n| Try without catch | Monadic error conversion |\n| Inline tests | Test blocks |\n| TDoc comments | Slash-star-hash markdown blocks |\n*/\n\n// ═══════════════════════════════════════════════════════════\n// 2. PARAMETER SYNTAX\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Parameters\n\nColon `:` = required (example value infers type).\nEquals `=` = optional (default value).\nQuestion mark `?:` = optional (TS-style).\n*/\n\n// Required params (colon shorthand)\nfunction greet(name: 'Alice') -> 'Hello, Alice' {\n return 'Hello, ' + name\n}\n\n// Optional params (equals = default)\nfunction greetOpt(name = 'World') -> 'Hello, World' {\n return 'Hello, ' + name\n}\n\n// Destructured object params (colon = required, equals = optional)\nfunction createUser({ name: 'Anon', role = 'user' }) -> { name: '', role: '' } {\n return { name, role }\n}\n\n// Numeric type narrowing: 42 = integer, 3.14 = float, +0 = non-negative int\nfunction calc(count: 42, rate: 3.14, index: +0) -> 0.0 {\n return (count + index) * rate\n}\n\ntest 'parameter syntax' {\n expect(greet('Bob')).toBe('Hello, Bob')\n expect(greetOpt()).toBe('Hello, World')\n expect(createUser({ name: 'Eve' })).toEqual({ name: 'Eve', role: 'user' })\n expect(calc(10, 1.5, 2)).toBe(18)\n}\n\n// ═══════════════════════════════════════════════════════════\n// 3. RETURN TYPES\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Return Types\n\n`->` signature test at transpile time.\n`-?` signature test + runtime output validation.\n`-!` skip signature test entirely.\n*/\n\n// -> : transpile-time check (double(5) must equal 10)\nfunction double(x: 5) -> 10 {\n return x * 2\n}\n\n// -! : skip test (useful when return shape varies)\nfunction safeDivide(a: 10, b: 2) -! 5 {\n if (b === 0) return { error: 'div by zero' }\n return a / b\n}\n\ntest 'return types' {\n expect(double(7)).toBe(14)\n expect(safeDivide(10, 0)).toEqual({ error: 'div by zero' })\n}\n\n// ═══════════════════════════════════════════════════════════\n// 4. SAFETY MARKERS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Safety Markers\n\n`!` = unsafe (skip input validation). Fast path for trusted callers.\n`?` = safe (force validation even inside `unsafe` blocks).\n*/\n\nfunction fastAdd(! a: 0, b: 0) -> 0 {\n return a + b\n}\n\nfunction safeAdd(? a: 0, b: 0) -> 0 {\n return a + b\n}\n\ntest 'safety markers' {\n expect(fastAdd(3, 4)).toBe(7)\n expect(safeAdd(3, 4)).toBe(7)\n}\n\n// ═══════════════════════════════════════════════════════════\n// 5. BARE ASSIGNMENTS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Bare Assignments\n\nUppercase identifiers auto-get `const`.\n*/\n\nGreeting = 'Hello'\nMaxRetries = 3\n\ntest 'bare assignments' {\n expect(Greeting).toBe('Hello')\n expect(MaxRetries).toBe(3)\n}\n\n// ═══════════════════════════════════════════════════════════\n// 7. CLASSES (callable without new)\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Classes\n\nWith `TjsClass` enabled, classes are callable without `new`.\n*/\n\nclass Point {\n constructor(x: 0.0, y: 0.0) {\n this.x = x\n this.y = y\n }\n\n magnitude() {\n return Math.sqrt(this.x * this.x + this.y * this.y)\n }\n}\n\ntest 'classes callable without new' {\n const p = Point(3, 4)\n expect(p instanceof Point).toBe(true)\n expect(p.magnitude()).toBe(5)\n}\n\n// ═══════════════════════════════════════════════════════════\n// 8. POLYMORPHIC FUNCTIONS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Polymorphic Functions\n\nSame name, different signatures. Dispatched by arity/type.\nSee the **Polymorphic Functions** example for more.\n*/\n\nfunction describe(value: 0) {\n return 'number: ' + value\n}\n\nfunction describe(first: '', last: '') {\n return first + ' ' + last\n}\n\ntest 'polymorphic dispatch by arity' {\n expect(describe(42)).toBe('number: 42')\n expect(describe('Jane', 'Doe')).toBe('Jane Doe')\n}\n\n// ═══════════════════════════════════════════════════════════\n// 9. POLYMORPHIC CONSTRUCTORS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Polymorphic Constructors\n\nMultiple `constructor()` declarations in a class.\nSee the **Polymorphic Constructors** example for more.\n*/\n\nclass Vec2 {\n constructor(x: 0.0, y: 0.0) {\n this.x = x\n this.y = y\n }\n\n constructor(obj: { x: 0.0, y: 0.0 }) {\n this.x = obj.x\n this.y = obj.y\n }\n}\n\ntest 'polymorphic constructors' {\n const a = Vec2(1, 2)\n const b = Vec2({ x: 1, y: 2 })\n expect(a.x).toBe(b.x)\n expect(a.y).toBe(b.y)\n}\n\n// ═══════════════════════════════════════════════════════════\n// 10. LOCAL EXTENSIONS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Local Extensions\n\nAdd methods to built-in types without prototype pollution.\nRewritten to `.call()` at transpile time for known types.\nSee the **Local Extensions** example for a runnable demo.\n\n extend String {\n capitalize() { return this[0].toUpperCase() + this.slice(1) }\n }\n\n extend Array {\n last() { return this[this.length - 1] }\n }\n\n 'hello'.capitalize() // 'Hello'\n [1, 2, 3].last() // 3\n*/\n\n// ═══════════════════════════════════════════════════════════\n// 11. EQUALITY OPERATORS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Equality\n\nWith `TjsEquals` enabled (at the top of this file):\n- `==` / `!=` use structural comparison (deep value equality)\n- `===` / `!==` are identity checks (same reference)\n- `Is` / `IsNot` are explicit structural operators (any mode)\n\n const a = { x: 1, y: [2, 3] }\n const b = { x: 1, y: [2, 3] }\n a == b // true (structural: same shape)\n a === b // false (identity: different objects)\n a Is b // true (explicit structural)\n a IsNot b // false\n*/\n\n// ═══════════════════════════════════════════════════════════\n// 12. TRY WITHOUT CATCH\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Try Without Catch\n\nA bare `try` block auto-converts exceptions to monadic errors.\n*/\n\nfunction parseJSON(s: '{\"a\":1}') -! { a: 1 } {\n try {\n return JSON.parse(s)\n }\n}\n\ntest 'try without catch' {\n expect(parseJSON('{\"ok\":true}')).toEqual({ ok: true })\n const bad = parseJSON('not json')\n expect(bad instanceof Error).toBe(true)\n}\n\n// ═══════════════════════════════════════════════════════════\n// 13. INLINE TESTS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Inline Tests\n\nTest blocks run at transpile time and are stripped from\noutput. They have full access to the module scope, so you\ncan test private functions without exporting them.\n*/\n\nfunction _private(x: 0) -> 0 {\n return x * x\n}\n\ntest 'inline tests can reach private functions' {\n expect(_private(5)).toBe(25)\n}\n\n// ═══════════════════════════════════════════════════════════\n// 14. MODULE EXPORTS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Module Exports\n\nStandard ES module syntax works. Functions and values\ncan be exported for use by other modules.\n*/\n\nexport function publicHelper(x: 0) -> 0 {\n return x + 1\n}\n\n// ═══════════════════════════════════════════════════════════\n// 15. TDOC COMMENTS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## TDoc Comments\n\nThese comment blocks (opened with slash-star-hash) contain\nmarkdown that becomes rich documentation in the playground\nand API docs. Every such block you've seen above is a TDoc.\n*/\n\n// ═══════════════════════════════════════════════════════════\n// OUTPUT\n// ═══════════════════════════════════════════════════════════\n\nconsole.log('TJS Grammar Reference — all tests passed!')\nconsole.log('Features demonstrated:', [\n 'safety directive', 'TJS modes', 'colon params', 'optional params',\n 'destructured params', 'numeric narrowing',\n 'return types (-> -? -!)', 'safety markers (! ?)',\n 'Type', 'Generic', 'Enum', 'Union', 'bare assignments',\n 'classes', 'polymorphic functions', 'polymorphic constructors',\n 'local extensions', 'structural equality', 'Is/IsNot',\n 'try without catch', 'inline tests', 'module exports', 'TDoc'\n].join(', '))",
176
+ "code": "// ═══════════════════════════════════════════════════════════\n// 1. SAFETY DIRECTIVE & TJS MODES\n// These must appear before any other code.\n// ═══════════════════════════════════════════════════════════\n\nsafety inputs\n\nTjsEquals\nTjsClass\n\n/*#\n# TJS Grammar Reference\n\nA runnable reference for TJS syntax. Each section demonstrates a\nfeature with a test proving it works.\n\n## Quick Index\n| Feature | Section |\n|---------|---------|\n| Safety & modes | `safety`, `TjsEquals`, `TjsClass` |\n| Parameters | Colon `:`, optional `=`, destructured `{}` |\n| Numeric narrowing | `42` int, `3.14` float, `+0` non-negative |\n| Return types | `->`, `-?`, `-!` |\n| Safety markers | `(! ...)` unsafe, `(? ...)` safe |\n| Type/Generic/Enum/Union | See above (requires full runtime) |\n| Bare assignments | `Uppercase = ...` |\n| Classes | Callable without `new` |\n| Polymorphic functions | Same name, different signatures |\n| Polymorphic constructors | Multiple `constructor()` |\n| Local extensions | `extend String { ... }` |\n| Equality | `==` structural, `===` identity, `Is`/`IsNot` |\n| Try without catch | Monadic error conversion |\n| Inline tests | Test blocks |\n| TDoc comments | Slash-star-hash markdown blocks |\n*/\n\n// ═══════════════════════════════════════════════════════════\n// 2. PARAMETER SYNTAX\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Parameters\n\nColon `:` = required (example value infers type).\nEquals `=` = optional (default value).\nQuestion mark `?:` = optional (TS-style).\n*/\n\n// Required params (colon shorthand)\nfunction greet(name: 'Alice') -> 'Hello, Alice' {\n return 'Hello, ' + name\n}\n\n// Optional params (equals = default)\nfunction greetOpt(name = 'World') -> 'Hello, World' {\n return 'Hello, ' + name\n}\n\n// Destructured object params (colon = required, equals = optional)\nfunction createUser({ name: 'Anon', role = 'user' }) -> { name: 'Anon', role: 'user' } {\n return { name, role }\n}\n\n// Numeric type narrowing: 42 = integer, 3.14 = float, +0 = non-negative int\nfunction calc(count: 42, rate: 3.14, index: +0) -> 131.88 {\n return (count + index) * rate\n}\n\ntest 'parameter syntax' {\n expect(greet('Bob')).toBe('Hello, Bob')\n expect(greetOpt()).toBe('Hello, World')\n expect(createUser({ name: 'Eve' })).toEqual({ name: 'Eve', role: 'user' })\n expect(calc(10, 1.5, 2)).toBe(18)\n}\n\n// ═══════════════════════════════════════════════════════════\n// 3. RETURN TYPES\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Return Types\n\n`->` signature test at transpile time.\n`-?` signature test + runtime output validation.\n`-!` skip signature test entirely.\n*/\n\n// -> : transpile-time check (double(5) must equal 10)\nfunction double(x: 5) -> 10 {\n return x * 2\n}\n\n// -! : skip test (useful when return shape varies)\nfunction safeDivide(a: 10, b: 2) -! 5 {\n if (b === 0) return { error: 'div by zero' }\n return a / b\n}\n\ntest 'return types' {\n expect(double(7)).toBe(14)\n expect(safeDivide(10, 0)).toEqual({ error: 'div by zero' })\n}\n\n// ═══════════════════════════════════════════════════════════\n// 4. SAFETY MARKERS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Safety Markers\n\n`!` = unsafe (skip input validation). Fast path for trusted callers.\n`?` = safe (force validation even inside `unsafe` blocks).\n*/\n\nfunction fastAdd(! a: 0, b: 0) -> 0 {\n return a + b\n}\n\nfunction safeAdd(? a: 0, b: 0) -> 0 {\n return a + b\n}\n\ntest 'safety markers' {\n expect(fastAdd(3, 4)).toBe(7)\n expect(safeAdd(3, 4)).toBe(7)\n}\n\n// ═══════════════════════════════════════════════════════════\n// 5. BARE ASSIGNMENTS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Bare Assignments\n\nUppercase identifiers auto-get `const`.\n*/\n\nGreeting = 'Hello'\nMaxRetries = 3\n\ntest 'bare assignments' {\n expect(Greeting).toBe('Hello')\n expect(MaxRetries).toBe(3)\n}\n\n// ═══════════════════════════════════════════════════════════\n// 7. CLASSES (callable without new)\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Classes\n\nWith `TjsClass` enabled, classes are callable without `new`.\n*/\n\nclass Point {\n constructor(x: 0.0, y: 0.0) {\n this.x = x\n this.y = y\n }\n\n magnitude() {\n return Math.sqrt(this.x * this.x + this.y * this.y)\n }\n}\n\ntest 'classes callable without new' {\n const p = Point(3, 4)\n expect(p instanceof Point).toBe(true)\n expect(p.magnitude()).toBe(5)\n}\n\n// ═══════════════════════════════════════════════════════════\n// 8. POLYMORPHIC FUNCTIONS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Polymorphic Functions\n\nSame name, different signatures. Dispatched by arity/type.\nSee the **Polymorphic Functions** example for more.\n*/\n\nfunction describe(value: 0) {\n return 'number: ' + value\n}\n\nfunction describe(first: '', last: '') {\n return first + ' ' + last\n}\n\ntest 'polymorphic dispatch by arity' {\n expect(describe(42)).toBe('number: 42')\n expect(describe('Jane', 'Doe')).toBe('Jane Doe')\n}\n\n// ═══════════════════════════════════════════════════════════\n// 9. POLYMORPHIC CONSTRUCTORS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Polymorphic Constructors\n\nMultiple `constructor()` declarations in a class.\nSee the **Polymorphic Constructors** example for more.\n*/\n\nclass Vec2 {\n constructor(x: 0.0, y: 0.0) {\n this.x = x\n this.y = y\n }\n\n constructor(obj: { x: 0.0, y: 0.0 }) {\n this.x = obj.x\n this.y = obj.y\n }\n}\n\ntest 'polymorphic constructors' {\n const a = Vec2(1, 2)\n const b = Vec2({ x: 1, y: 2 })\n expect(a.x).toBe(b.x)\n expect(a.y).toBe(b.y)\n}\n\n// ═══════════════════════════════════════════════════════════\n// 10. LOCAL EXTENSIONS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Local Extensions\n\nAdd methods to built-in types without prototype pollution.\nRewritten to `.call()` at transpile time for known types.\nSee the **Local Extensions** example for a runnable demo.\n\n extend String {\n capitalize() { return this[0].toUpperCase() + this.slice(1) }\n }\n\n extend Array {\n last() { return this[this.length - 1] }\n }\n\n 'hello'.capitalize() // 'Hello'\n [1, 2, 3].last() // 3\n*/\n\n// ═══════════════════════════════════════════════════════════\n// 11. EQUALITY OPERATORS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Equality\n\nWith `TjsEquals` enabled (at the top of this file):\n- `==` / `!=` use structural comparison (deep value equality)\n- `===` / `!==` are identity checks (same reference)\n- `Is` / `IsNot` are explicit structural operators (any mode)\n\n const a = { x: 1, y: [2, 3] }\n const b = { x: 1, y: [2, 3] }\n a == b // true (structural: same shape)\n a === b // false (identity: different objects)\n a Is b // true (explicit structural)\n a IsNot b // false\n*/\n\n// ═══════════════════════════════════════════════════════════\n// 12. TRY WITHOUT CATCH\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Try Without Catch\n\nA bare `try` block auto-converts exceptions to monadic errors.\n*/\n\nfunction parseJSON(s: '{\"a\":1}') -! { a: 1 } {\n try {\n return JSON.parse(s)\n }\n}\n\ntest 'try without catch' {\n expect(parseJSON('{\"ok\":true}')).toEqual({ ok: true })\n const bad = parseJSON('not json')\n expect(bad instanceof Error).toBe(true)\n}\n\n// ═══════════════════════════════════════════════════════════\n// 13. INLINE TESTS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Inline Tests\n\nTest blocks run at transpile time and are stripped from\noutput. They have full access to the module scope, so you\ncan test private functions without exporting them.\n*/\n\nfunction _private(x: 0) -> 0 {\n return x * x\n}\n\ntest 'inline tests can reach private functions' {\n expect(_private(5)).toBe(25)\n}\n\n// ═══════════════════════════════════════════════════════════\n// 14. MODULE EXPORTS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## Module Exports\n\nStandard ES module syntax works. Functions and values\ncan be exported for use by other modules.\n*/\n\nexport function publicHelper(x: 0) -> 1 {\n return x + 1\n}\n\n// ═══════════════════════════════════════════════════════════\n// 15. TDOC COMMENTS\n// ═══════════════════════════════════════════════════════════\n\n/*#\n## TDoc Comments\n\nThese comment blocks (opened with slash-star-hash) contain\nmarkdown that becomes rich documentation in the playground\nand API docs. Every such block you've seen above is a TDoc.\n*/\n\n// ═══════════════════════════════════════════════════════════\n// OUTPUT\n// ═══════════════════════════════════════════════════════════\n\nconsole.log('TJS Grammar Reference — all tests passed!')\nconsole.log('Features demonstrated:', [\n 'safety directive', 'TJS modes', 'colon params', 'optional params',\n 'destructured params', 'numeric narrowing',\n 'return types (-> -? -!)', 'safety markers (! ?)',\n 'Type', 'Generic', 'Enum', 'Union', 'bare assignments',\n 'classes', 'polymorphic functions', 'polymorphic constructors',\n 'local extensions', 'structural equality', 'Is/IsNot',\n 'try without catch', 'inline tests', 'module exports', 'TDoc'\n].join(', '))",
177
177
  "language": "tjs",
178
178
  "description": "Comprehensive reference covering all major TJS syntax features. **Type declarations** (require full `tjs-lang` runtime — shown here for reference): Type Name = 'Alice' Type Age 'a non-negative age' { example: 25 predicate(x) { return typeof x === 'number' && x >= 0 } } Generic Pair<A, B> { description: 'a pair of values' predicate(obj, A, B) { ... } } Enum Direction 'cardinal direction' { North, East, South, West } Enum Color 'CSS color' { Red = 'red', Green = 'green', Blue = 'blue' } Union Status 'task status' 'pending' | 'active' | 'done' All other features are exercised in the runnable code below:"
179
179
  },
@@ -197,7 +197,7 @@
197
197
  "type": "example",
198
198
  "group": "fullstack",
199
199
  "order": 12,
200
- "code": "/**\n * # User Service\n *\n * A complete backend service running in the browser.\n * Save this module as \"user-service\", then run the client example.\n *\n * Features:\n * - Type-safe endpoints with validation\n * - In-memory data store\n * - Full CRUD operations\n */\n\n// In-memory store (would be a real DB in production)\nconst users = new Map()\nlet nextId = 1\n\n// Create a new user\nexport function createUser(input: {\n name: 'Alice',\n email: 'alice@example.com'\n}) -> { id: 0, name: '', email: '', createdAt: '' } {\n const user = {\n id: nextId++,\n name: input.name,\n email: input.email,\n createdAt: new Date().toISOString()\n }\n users.set(user.id, user)\n return user\n}\n\n// Get user by ID (returns empty object if not found - union types not yet supported)\nexport function getUser(input: { id: 1 }) -> { id: 0, name: '', email: '', createdAt: '' } {\n return users.get(input.id) || { id: 0, name: '', email: '', createdAt: '' }\n}\n\n// Update a user (returns empty object if not found - union types not yet supported)\nexport function updateUser(input: {\n id: 1,\n name: 'Alice',\n email: 'alice@example.com'\n}) -> { id: 0, name: '', email: '', createdAt: '' } {\n const existing = users.get(input.id)\n if (!existing) return { id: 0, name: '', email: '', createdAt: '' }\n\n const updated = { ...existing, name: input.name, email: input.email }\n users.set(input.id, updated)\n return updated\n}\n\n// Delete a user\nexport function deleteUser(input: { id: 1 }) -> { success: true, deleted: 0 } {\n const existed = users.has(input.id)\n users.delete(input.id)\n return { success: existed, deleted: existed ? input.id : 0 }\n}\n\n// List all users\nexport function listUsers(input: { limit: 10, offset: 0 })\n -> { users: [{ id: 0, name: '', email: '', createdAt: '' }], total: 0 } {\n const all = [...users.values()]\n const slice = all.slice(input.offset, input.offset + input.limit)\n return { users: slice, total: all.length }\n}\n\n// Search users by name\nexport function searchUsers(input: { query: '' })\n -> { users: [{ id: 0, name: '', email: '', createdAt: '' }] } {\n const query = input.query.toLowerCase()\n const matches = [...users.values()].filter(u =>\n u.name.toLowerCase().includes(query)\n )\n return { users: matches }\n}\n\n// Test the service\ntest('createUser creates user with ID') {\n const user = createUser({ name: 'Test', email: 'test@test.com' })\n expect(user.id).toBeGreaterThan(0)\n expect(user.name).toBe('Test')\n}\n\ntest('getUser returns created user') {\n const created = createUser({ name: 'Bob', email: 'bob@test.com' })\n const fetched = getUser({ id: created.id })\n expect(fetched?.name).toBe('Bob')\n}\n\ntest('updateUser modifies user') {\n const user = createUser({ name: 'Original', email: 'orig@test.com' })\n const updated = updateUser({ id: user.id, name: 'Updated', email: 'new@test.com' })\n expect(updated?.name).toBe('Updated')\n}\n\ntest('deleteUser removes user') {\n const user = createUser({ name: 'ToDelete', email: 'del@test.com' })\n const result = deleteUser({ id: user.id })\n expect(result.success).toBe(true)\n // getUser returns empty object when not found (not null)\n expect(getUser({ id: user.id }).name).toBe('')\n}\n\n// Demo\nconsole.log('=== User Service Demo ===\\\\n')\n\nconst alice = createUser({ name: 'Alice', email: 'alice@company.com' })\nconsole.log('Created:', alice)\n\nconst bob = createUser({ name: 'Bob', email: 'bob@company.com' })\nconsole.log('Created:', bob)\n\nconst carol = createUser({ name: 'Carol', email: 'carol@company.com' })\nconsole.log('Created:', carol)\n\nconsole.log('\\\\nAll users:', listUsers({ limit: 10, offset: 0 }))\nconsole.log('\\\\nSearch \"ob\":', searchUsers({ query: 'ob' }))\n\n// Type validation in action (safe mode catches wrong types)\nconsole.log('\\\\nType validation test:')\nconsole.log('createUser({ name: 123 }) would return a type error in safe mode')",
200
+ "code": "/**\n * # User Service\n *\n * A complete backend service running in the browser.\n * Save this module as \"user-service\", then run the client example.\n *\n * Features:\n * - Type-safe endpoints with validation\n * - In-memory data store\n * - Full CRUD operations\n */\n\n// In-memory store (would be a real DB in production)\nconst users = new Map()\nlet nextId = 1\n\n// Create a new user\nexport function createUser(input: {\n name: 'Alice',\n email: 'alice@example.com'\n}) -! { id: 0, name: '', email: '', createdAt: '' } {\n const user = {\n id: nextId++,\n name: input.name,\n email: input.email,\n createdAt: new Date().toISOString()\n }\n users.set(user.id, user)\n return user\n}\n\n// Get user by ID (returns empty object if not found - union types not yet supported)\nexport function getUser(input: { id: 1 }) -! { id: 0, name: '', email: '', createdAt: '' } {\n return users.get(input.id) || { id: 0, name: '', email: '', createdAt: '' }\n}\n\n// Update a user (returns empty object if not found - union types not yet supported)\nexport function updateUser(input: {\n id: 1,\n name: 'Alice',\n email: 'alice@example.com'\n}) -! { id: 0, name: '', email: '', createdAt: '' } {\n const existing = users.get(input.id)\n if (!existing) return { id: 0, name: '', email: '', createdAt: '' }\n\n const updated = { ...existing, name: input.name, email: input.email }\n users.set(input.id, updated)\n return updated\n}\n\n// Delete a user\nexport function deleteUser(input: { id: 1 }) -! { success: true, deleted: 0 } {\n const existed = users.has(input.id)\n users.delete(input.id)\n return { success: existed, deleted: existed ? input.id : 0 }\n}\n\n// List all users\nexport function listUsers(input: { limit: 10, offset: 0 })\n -! { users: [{ id: 0, name: '', email: '', createdAt: '' }], total: 0 } {\n const all = [...users.values()]\n const slice = all.slice(input.offset, input.offset + input.limit)\n return { users: slice, total: all.length }\n}\n\n// Search users by name\nexport function searchUsers(input: { query: '' })\n -! { users: [{ id: 0, name: '', email: '', createdAt: '' }] } {\n const query = input.query.toLowerCase()\n const matches = [...users.values()].filter(u =>\n u.name.toLowerCase().includes(query)\n )\n return { users: matches }\n}\n\n// Test the service\ntest('createUser creates user with ID') {\n const user = createUser({ name: 'Test', email: 'test@test.com' })\n expect(user.id).toBeGreaterThan(0)\n expect(user.name).toBe('Test')\n}\n\ntest('getUser returns created user') {\n const created = createUser({ name: 'Bob', email: 'bob@test.com' })\n const fetched = getUser({ id: created.id })\n expect(fetched?.name).toBe('Bob')\n}\n\ntest('updateUser modifies user') {\n const user = createUser({ name: 'Original', email: 'orig@test.com' })\n const updated = updateUser({ id: user.id, name: 'Updated', email: 'new@test.com' })\n expect(updated?.name).toBe('Updated')\n}\n\ntest('deleteUser removes user') {\n const user = createUser({ name: 'ToDelete', email: 'del@test.com' })\n const result = deleteUser({ id: user.id })\n expect(result.success).toBe(true)\n // getUser returns empty object when not found (not null)\n expect(getUser({ id: user.id }).name).toBe('')\n}\n\n// Demo\nconsole.log('=== User Service Demo ===\\\\n')\n\nconst alice = createUser({ name: 'Alice', email: 'alice@company.com' })\nconsole.log('Created:', alice)\n\nconst bob = createUser({ name: 'Bob', email: 'bob@company.com' })\nconsole.log('Created:', bob)\n\nconst carol = createUser({ name: 'Carol', email: 'carol@company.com' })\nconsole.log('Created:', carol)\n\nconsole.log('\\\\nAll users:', listUsers({ limit: 10, offset: 0 }))\nconsole.log('\\\\nSearch \"ob\":', searchUsers({ query: 'ob' }))\n\n// Type validation in action (safe mode catches wrong types)\nconsole.log('\\\\nType validation test:')\nconsole.log('createUser({ name: 123 }) would return a type error in safe mode')",
201
201
  "language": "tjs",
202
202
  "description": "A complete backend service with typed endpoints - save this first!"
203
203
  },
@@ -221,7 +221,7 @@
221
221
  "type": "example",
222
222
  "group": "fullstack",
223
223
  "order": 14,
224
- "code": "/**\n * # Todo API Service\n *\n * A REST-style API for todo management.\n * Demonstrates a more complete service pattern.\n */\n\n// Simulated persistence layer\nconst todos = new Map()\nlet nextId = 1\n\n// Types are inferred from function signatures below\n// Todo: { id: 0, title: '', completed: false, createdAt: '' }\n// CreateInput: { title: 'Buy milk' }\n// UpdateInput: { id: 1, title: 'Buy milk', completed: false }\n\n// POST /todos - Create\nexport function createTodo(input: { title: 'New todo' })\n -> { id: 0, title: '', completed: false, createdAt: '' } {\n const todo = {\n id: nextId++,\n title: input.title,\n completed: false,\n createdAt: new Date().toISOString()\n }\n todos.set(todo.id, todo)\n return todo\n}\n\n// GET /todos/:id - Read one (returns empty if not found)\nexport function getTodo(input: { id: 1 })\n -> { id: 0, title: '', completed: false, createdAt: '' } {\n return todos.get(input.id) || { id: 0, title: '', completed: false, createdAt: '' }\n}\n\n// GET /todos - Read all (with optional filter)\nexport function listTodos(input = { completed: false })\n -> { todos: [{ id: 0, title: '', completed: false, createdAt: '' }] } {\n let items = [...todos.values()]\n\n if (input.completed !== undefined) {\n items = items.filter(t => t.completed === input.completed)\n }\n\n return { todos: items }\n}\n\n// PUT /todos/:id - Update (returns empty if not found)\nexport function updateTodo(input: { id: 1, title: '', completed: false })\n -> { id: 0, title: '', completed: false, createdAt: '' } {\n const existing = todos.get(input.id)\n if (!existing) return { id: 0, title: '', completed: false, createdAt: '' }\n\n const updated = {\n ...existing,\n title: input.title ?? existing.title,\n completed: input.completed ?? existing.completed\n }\n todos.set(input.id, updated)\n return updated\n}\n\n// DELETE /todos/:id - Delete\nexport function deleteTodo(input: { id: 1 }) -> { deleted: true } {\n const existed = todos.has(input.id)\n todos.delete(input.id)\n return { deleted: existed }\n}\n\n// PATCH /todos/:id/toggle - Toggle completion (returns empty if not found)\nexport function toggleTodo(input: { id: 1 })\n -> { id: 0, title: '', completed: false, createdAt: '' } {\n const todo = todos.get(input.id)\n if (!todo) return { id: 0, title: '', completed: false, createdAt: '' }\n\n todo.completed = !todo.completed\n return todo\n}\n\n// DELETE /todos/completed - Clear completed\nexport function clearCompleted(input: {}) -> { cleared: 0 } {\n let cleared = 0\n for (const [id, todo] of todos) {\n if (todo.completed) {\n todos.delete(id)\n cleared++\n }\n }\n return { cleared }\n}\n\n// Tests\ntest('CRUD operations work') {\n const todo = createTodo({ title: 'Test todo' })\n expect(todo.id).toBeGreaterThan(0)\n expect(todo.completed).toBe(false)\n\n const fetched = getTodo({ id: todo.id })\n expect(fetched?.title).toBe('Test todo')\n\n const toggled = toggleTodo({ id: todo.id })\n expect(toggled?.completed).toBe(true)\n\n const deleted = deleteTodo({ id: todo.id })\n expect(deleted.deleted).toBe(true)\n}\n\n// Demo\nconsole.log('=== Todo API Demo ===\\\\n')\n\n// Create todos\ncreateTodo({ title: 'Learn TJS' })\ncreateTodo({ title: 'Build something cool' })\ncreateTodo({ title: 'Ship it' })\n\nconsole.log('Created 3 todos')\nconsole.log('All:', listTodos({}))\n\n// Complete first one\nconst first = listTodos({}).todos[0]\ntoggleTodo({ id: first.id })\nconsole.log('\\\\nToggled first todo')\nconsole.log('Completed:', listTodos({ completed: true }))\nconsole.log('Pending:', listTodos({ completed: false }))\n\n// Clear completed\nconsole.log('\\\\nClearing completed...')\nconsole.log(clearCompleted({}))\nconsole.log('Remaining:', listTodos({}))",
224
+ "code": "/**\n * # Todo API Service\n *\n * A REST-style API for todo management.\n * Demonstrates a more complete service pattern.\n */\n\n// Simulated persistence layer\nconst todos = new Map()\nlet nextId = 1\n\n// Types are inferred from function signatures below\n// Todo: { id: 0, title: '', completed: false, createdAt: '' }\n// CreateInput: { title: 'Buy milk' }\n// UpdateInput: { id: 1, title: 'Buy milk', completed: false }\n\n// POST /todos - Create\nexport function createTodo(input: { title: 'New todo' })\n -! { id: 0, title: '', completed: false, createdAt: '' } {\n const todo = {\n id: nextId++,\n title: input.title,\n completed: false,\n createdAt: new Date().toISOString()\n }\n todos.set(todo.id, todo)\n return todo\n}\n\n// GET /todos/:id - Read one (returns empty if not found)\nexport function getTodo(input: { id: 1 })\n -! { id: 0, title: '', completed: false, createdAt: '' } {\n return todos.get(input.id) || { id: 0, title: '', completed: false, createdAt: '' }\n}\n\n// GET /todos - Read all (with optional filter)\nexport function listTodos(input = { completed: false })\n -! { todos: [{ id: 0, title: '', completed: false, createdAt: '' }] } {\n let items = [...todos.values()]\n\n if (input.completed !== undefined) {\n items = items.filter(t => t.completed === input.completed)\n }\n\n return { todos: items }\n}\n\n// PUT /todos/:id - Update (returns empty if not found)\nexport function updateTodo(input: { id: 1, title: '', completed: false })\n -! { id: 0, title: '', completed: false, createdAt: '' } {\n const existing = todos.get(input.id)\n if (!existing) return { id: 0, title: '', completed: false, createdAt: '' }\n\n const updated = {\n ...existing,\n title: input.title ?? existing.title,\n completed: input.completed ?? existing.completed\n }\n todos.set(input.id, updated)\n return updated\n}\n\n// DELETE /todos/:id - Delete\nexport function deleteTodo(input: { id: 1 }) -! { deleted: true } {\n const existed = todos.has(input.id)\n todos.delete(input.id)\n return { deleted: existed }\n}\n\n// PATCH /todos/:id/toggle - Toggle completion (returns empty if not found)\nexport function toggleTodo(input: { id: 1 })\n -! { id: 0, title: '', completed: false, createdAt: '' } {\n const todo = todos.get(input.id)\n if (!todo) return { id: 0, title: '', completed: false, createdAt: '' }\n\n todo.completed = !todo.completed\n return todo\n}\n\n// DELETE /todos/completed - Clear completed\nexport function clearCompleted(input: {}) -! { cleared: 0 } {\n let cleared = 0\n for (const [id, todo] of todos) {\n if (todo.completed) {\n todos.delete(id)\n cleared++\n }\n }\n return { cleared }\n}\n\n// Tests\ntest('CRUD operations work') {\n const todo = createTodo({ title: 'Test todo' })\n expect(todo.id).toBeGreaterThan(0)\n expect(todo.completed).toBe(false)\n\n const fetched = getTodo({ id: todo.id })\n expect(fetched?.title).toBe('Test todo')\n\n const toggled = toggleTodo({ id: todo.id })\n expect(toggled?.completed).toBe(true)\n\n const deleted = deleteTodo({ id: todo.id })\n expect(deleted.deleted).toBe(true)\n}\n\n// Demo\nconsole.log('=== Todo API Demo ===\\\\n')\n\n// Create todos\ncreateTodo({ title: 'Learn TJS' })\ncreateTodo({ title: 'Build something cool' })\ncreateTodo({ title: 'Ship it' })\n\nconsole.log('Created 3 todos')\nconsole.log('All:', listTodos({}))\n\n// Complete first one\nconst first = listTodos({}).todos[0]\ntoggleTodo({ id: first.id })\nconsole.log('\\\\nToggled first todo')\nconsole.log('Completed:', listTodos({ completed: true }))\nconsole.log('Pending:', listTodos({ completed: false }))\n\n// Clear completed\nconsole.log('\\\\nClearing completed...')\nconsole.log(clearCompleted({}))\nconsole.log('Remaining:', listTodos({}))",
225
225
  "language": "tjs",
226
226
  "description": "Complete REST-style Todo API with persistence"
227
227
  },
@@ -257,7 +257,7 @@
257
257
  "type": "example",
258
258
  "group": "patterns",
259
259
  "order": 7,
260
- "code": "/*#\n## Monadic Error Propagation\n\nType errors are values (MonadicError), not exceptions. They propagate\nautomatically through function chains — if any function receives an\nerror as input, it short-circuits and returns the error immediately.\n\nNo try/catch needed. No manual error checking between calls.\n*/\n\n// --- Error propagation through a pipeline ---\n\nfunction validate(name: '') -> '' {\n return name.trim()\n}\n\nfunction greet(name: '') -> '' {\n return `Hello, ${name}!`\n}\n\nfunction shout(text: '') -> '' {\n return text.toUpperCase()\n}\n\ntest 'valid input flows through the pipeline' {\n // Each function's output feeds the next function's input\n const result = shout(greet(validate('alice')))\n expect(result).toBe('HELLO, ALICE!')\n}\n\ntest 'type error propagates through the entire chain' {\n // validate(42) returns a MonadicError (42 is not a string)\n // greet() receives the error, short-circuits, returns it\n // shout() receives the error, short-circuits, returns it\n const result = shout(greet(validate(42)))\n expect(result instanceof Error).toBe(true)\n expect(result.message.includes('string')).toBe(true)\n}\n\ntest 'error identity is preserved (same object, not a copy)' {\n const err = validate(42)\n expect(greet(err)).toBe(err)\n expect(shout(err)).toBe(err)\n}\n\n// --- Result pattern for domain errors ---\n\nfunction divide(a: 10, b: 2) -> { value: 0, error = '' } {\n if (b === 0) {\n return { value: NaN, error: 'Division by zero' }\n }\n return { value: a / b }\n}\n\ntest 'divide handles zero' {\n const result = divide(10, 0)\n expect(result.error).toBe('Division by zero')\n}\n\ntest 'divide works normally' {\n const result = divide(10, 2)\n expect(result.value).toBe(5)\n}\n\n// Errors propagate when passed as arguments to TJS functions.\n// If you use a potentially-error value in a JS expression (e.g. result.length),\n// check it first: if (result instanceof Error) return result\n// In debug mode, errors include a callStack showing the full call chain.",
260
+ "code": "/*#\n## Monadic Error Propagation\n\nType errors are values (MonadicError), not exceptions. They propagate\nautomatically through function chains — if any function receives an\nerror as input, it short-circuits and returns the error immediately.\n\nNo try/catch needed. No manual error checking between calls.\n*/\n\n// --- Error propagation through a pipeline ---\n\nfunction validate(name: '') -> '' {\n return name.trim()\n}\n\nfunction greet(name: '') -> 'Hello, !' {\n return `Hello, ${name}!`\n}\n\nfunction shout(text: '') -> '' {\n return text.toUpperCase()\n}\n\ntest 'valid input flows through the pipeline' {\n // Each function's output feeds the next function's input\n const result = shout(greet(validate('alice')))\n expect(result).toBe('HELLO, ALICE!')\n}\n\ntest 'type error propagates through the entire chain' {\n // validate(42) returns a MonadicError (42 is not a string)\n // greet() receives the error, short-circuits, returns it\n // shout() receives the error, short-circuits, returns it\n const result = shout(greet(validate(42)))\n expect(result instanceof Error).toBe(true)\n expect(result.message.includes('string')).toBe(true)\n}\n\ntest 'error identity is preserved (same object, not a copy)' {\n const err = validate(42)\n expect(greet(err)).toBe(err)\n expect(shout(err)).toBe(err)\n}\n\n// --- Result pattern for domain errors ---\n\nfunction divide(a: 10, b: 2) -> { value: 5 } {\n if (b === 0) {\n return { value: NaN, error: 'Division by zero' }\n }\n return { value: a / b }\n}\n\ntest 'divide handles zero' {\n const result = divide(10, 0)\n expect(result.error).toBe('Division by zero')\n}\n\ntest 'divide works normally' {\n const result = divide(10, 2)\n expect(result.value).toBe(5)\n}\n\n// Errors propagate when passed as arguments to TJS functions.\n// If you use a potentially-error value in a JS expression (e.g. result.length),\n// check it first: if (result instanceof Error) return result\n// In debug mode, errors include a callStack showing the full call chain.",
261
261
  "language": "tjs",
262
262
  "description": "Monadic error propagation and type-safe error patterns"
263
263
  },