tjs-lang 0.6.8 → 0.6.9
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 +9 -9
- package/dist/index.js +4 -5
- package/dist/index.js.map +3 -3
- package/dist/tjs-full.js +4 -5
- package/dist/tjs-full.js.map +3 -3
- package/package.json +1 -1
- package/src/cli/tjs.ts +1 -1
- package/src/lang/codegen.test.ts +10 -10
- package/src/lang/emitters/js-tests.ts +10 -11
- package/src/lang/features.test.ts +125 -15
- package/src/lang/parser.test.ts +4 -4
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: '') ->
|
|
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: '' }) -> '
|
|
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: [
|
|
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) ->
|
|
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})
|
|
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
|
|
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:
|
|
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
|
},
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var M8=Object.defineProperty;var w8=(Z,$)=>()=>($||Z(($={exports:{}}).exports,$),$.exports);var F8=(Z)=>Z;function j8(Z,$){this[Z]=F8.bind(null,$)}var P8=(Z,$)=>{for(var X in $)M8(Z,X,{get:$[X],enumerable:!0,configurable:!0,set:j8.bind($,X)})};var V8=(Z,$)=>()=>(Z&&($=Z(Z=0)),$);var j4=((Z)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(Z,{get:($,X)=>(typeof require<"u"?require:$)[X]}):Z)(function(Z){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+Z+'" is not supported')});var G7=w8(($K,aZ)=>{aZ.exports={name:"tjs-lang",version:"0.6.
|
|
1
|
+
var M8=Object.defineProperty;var w8=(Z,$)=>()=>($||Z(($={exports:{}}).exports,$),$.exports);var F8=(Z)=>Z;function j8(Z,$){this[Z]=F8.bind(null,$)}var P8=(Z,$)=>{for(var X in $)M8(Z,X,{get:$[X],enumerable:!0,configurable:!0,set:j8.bind($,X)})};var V8=(Z,$)=>()=>(Z&&($=Z(Z=0)),$);var j4=((Z)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(Z,{get:($,X)=>(typeof require<"u"?require:$)[X]}):Z)(function(Z){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+Z+'" is not supported')});var G7=w8(($K,aZ)=>{aZ.exports={name:"tjs-lang",version:"0.6.9",description:"Type-safe JavaScript dialect with runtime validation, sandboxed VM execution, and AI agent orchestration. Transpiles TypeScript to validated JS with fuel-metered execution for untrusted code.",keywords:["typescript","transpiler","runtime-validation","type-safety","sandbox","virtual-machine","wasm-alternative","ai-agents","llm","orchestration","security","fuel-metering","capability-based","json-ast","untrusted-code"],license:"Apache-2.0",main:"./dist/index.js",exports:{".":{bun:"./src/index.ts",default:"./dist/index.js"},"./eval":{bun:"./src/lang/eval.ts",default:"./dist/lang/eval.js"},"./lang":{bun:"./src/lang/index.ts",default:"./dist/lang/index.js"},"./lang/eval":{bun:"./src/lang/eval.ts",default:"./dist/lang/eval.js"},"./lang/from-ts":{bun:"./src/lang/emitters/from-ts.ts",default:"./dist/lang/emitters/from-ts.js"},"./src":"./src/index.ts","./editors/monaco":"./editors/monaco/ajs-monarch.js","./editors/codemirror":"./editors/codemirror/ajs-language.js","./editors/ace":"./editors/ace/ajs-mode.js"},bin:{tjs:"./src/cli/tjs.ts",tjsx:"./src/cli/tjsx.ts","tjs-playground":"./src/cli/playground.ts","create-tjs-app":"./src/cli/create-app.ts","ajs-install-vscode":"./bin/install-vscode.sh","ajs-install-cursor":"./bin/install-cursor.sh"},type:"module",files:["dist","src","docs","editors","bin","demo","tjs-lang.svg","CONTEXT.md","CLAUDE.md"],sideEffects:!1,repository:{type:"git",url:"https://github.com/tonioloewald/tjs-lang.git"},devDependencies:{"@codemirror/lang-javascript":"^6.2.4","@codemirror/state":"^6.5.3","@codemirror/view":"^6.39.9","@happy-dom/global-registrator":"^20.1.0","@types/bun":"latest","@types/jsdom":"^21.1.7","@typescript-eslint/eslint-plugin":"^5.62.0","@typescript-eslint/parser":"^5.62.0","acorn-walk":"^8.3.4",chokidar:"^4.0.3",codemirror:"^6.0.2",eslint:"^8.57.1","firebase-admin":"^13.6.0","firebase-functions":"^7.0.5",marked:"^9.1.6",prettier:"^2.8.8",tosijs:"^1.2.0","tosijs-ui":"^1.2.0",typescript:"^5.6.2",valibot:"^0.36.0",vitest:"^2.0.5"},scripts:{format:"bun eslint src --fix && bun prettier --write .",lint:"eslint src","build:grammars":"bun editors/build-grammars.ts","test:fast":"SKIP_LLM_TESTS=1 SKIP_BENCHMARKS=1 bun test","test:llm":"bun test src/batteries/models.integration.test.ts",bench:"bun bin/benchmarks.ts",make:"rm -rf dist && bun format && bun run build:grammars && tsc -p tsconfig.build.json && bun scripts/build.ts","build:bundles":"bun scripts/build.ts",typecheck:"tsc --noEmit",latest:"rm -rf node_modules && bun install",docs:"node bin/docs.js",dev:"bun run bin/dev.ts","build:demo":"bun scripts/build-demo.ts","build:cli":"bun build src/cli/tjs.ts --compile --outfile=dist/tjs && bun build src/cli/tjsx.ts --compile --outfile=dist/tjsx","functions:build":"cd functions && npm run build","functions:deploy":"cd functions && npm run deploy","functions:serve":"cd functions && npm run serve","deploy:hosting":"firebase deploy --only hosting",deploy:"npm run build:demo && npm run functions:deploy && firebase deploy --only hosting",start:"bun run build:demo && bun run dev"},dependencies:{"@codemirror/lang-css":"^6.3.1","@codemirror/lang-html":"^6.4.11","@codemirror/lang-markdown":"^6.5.0","@codemirror/theme-one-dark":"^6.1.3",acorn:"^8.15.0",firebase:"^10.12.0","tosijs-schema":"^1.2.0"}}});var Y6={};P8(Y6,{sep:()=>X8,resolve:()=>I4,relative:()=>s7,posix:()=>K8,parse:()=>$8,normalize:()=>H6,join:()=>o7,isAbsolute:()=>c7,format:()=>Z8,extname:()=>e7,dirname:()=>r7,delimiter:()=>Q8,default:()=>t$,basename:()=>t7,_makeLong:()=>a7});function B1(Z){if(typeof Z!=="string")throw TypeError("Path must be a string. Received "+JSON.stringify(Z))}function n7(Z,$){var X="",Q=0,K=-1,H=0,Y;for(var z=0;z<=Z.length;++z){if(z<Z.length)Y=Z.charCodeAt(z);else if(Y===47)break;else Y=47;if(Y===47){if(K===z-1||H===1);else if(K!==z-1&&H===2){if(X.length<2||Q!==2||X.charCodeAt(X.length-1)!==46||X.charCodeAt(X.length-2)!==46){if(X.length>2){var W=X.lastIndexOf("/");if(W!==X.length-1){if(W===-1)X="",Q=0;else X=X.slice(0,W),Q=X.length-1-X.lastIndexOf("/");K=z,H=0;continue}}else if(X.length===2||X.length===1){X="",Q=0,K=z,H=0;continue}}if($){if(X.length>0)X+="/..";else X="..";Q=2}}else{if(X.length>0)X+="/"+Z.slice(K+1,z);else X=Z.slice(K+1,z);Q=z-K-1}K=z,H=0}else if(Y===46&&H!==-1)++H;else H=-1}return X}function r$(Z,$){var X=$.dir||$.root,Q=$.base||($.name||"")+($.ext||"");if(!X)return Q;if(X===$.root)return X+Q;return X+Z+Q}function I4(){var Z="",$=!1,X;for(var Q=arguments.length-1;Q>=-1&&!$;Q--){var K;if(Q>=0)K=arguments[Q];else{if(X===void 0)X=process.cwd();K=X}if(B1(K),K.length===0)continue;Z=K+"/"+Z,$=K.charCodeAt(0)===47}if(Z=n7(Z,!$),$)if(Z.length>0)return"/"+Z;else return"/";else if(Z.length>0)return Z;else return"."}function H6(Z){if(B1(Z),Z.length===0)return".";var $=Z.charCodeAt(0)===47,X=Z.charCodeAt(Z.length-1)===47;if(Z=n7(Z,!$),Z.length===0&&!$)Z=".";if(Z.length>0&&X)Z+="/";if($)return"/"+Z;return Z}function c7(Z){return B1(Z),Z.length>0&&Z.charCodeAt(0)===47}function o7(){if(arguments.length===0)return".";var Z;for(var $=0;$<arguments.length;++$){var X=arguments[$];if(B1(X),X.length>0)if(Z===void 0)Z=X;else Z+="/"+X}if(Z===void 0)return".";return H6(Z)}function s7(Z,$){if(B1(Z),B1($),Z===$)return"";if(Z=I4(Z),$=I4($),Z===$)return"";var X=1;for(;X<Z.length;++X)if(Z.charCodeAt(X)!==47)break;var Q=Z.length,K=Q-X,H=1;for(;H<$.length;++H)if($.charCodeAt(H)!==47)break;var Y=$.length,z=Y-H,W=K<z?K:z,G=-1,J=0;for(;J<=W;++J){if(J===W){if(z>W){if($.charCodeAt(H+J)===47)return $.slice(H+J+1);else if(J===0)return $.slice(H+J)}else if(K>W){if(Z.charCodeAt(X+J)===47)G=J;else if(J===0)G=0}break}var U=Z.charCodeAt(X+J),_=$.charCodeAt(H+J);if(U!==_)break;else if(U===47)G=J}var L="";for(J=X+G+1;J<=Q;++J)if(J===Q||Z.charCodeAt(J)===47)if(L.length===0)L+="..";else L+="/..";if(L.length>0)return L+$.slice(H+G);else{if(H+=G,$.charCodeAt(H)===47)++H;return $.slice(H)}}function a7(Z){return Z}function r7(Z){if(B1(Z),Z.length===0)return".";var $=Z.charCodeAt(0),X=$===47,Q=-1,K=!0;for(var H=Z.length-1;H>=1;--H)if($=Z.charCodeAt(H),$===47){if(!K){Q=H;break}}else K=!1;if(Q===-1)return X?"/":".";if(X&&Q===1)return"//";return Z.slice(0,Q)}function t7(Z,$){if($!==void 0&&typeof $!=="string")throw TypeError('"ext" argument must be a string');B1(Z);var X=0,Q=-1,K=!0,H;if($!==void 0&&$.length>0&&$.length<=Z.length){if($.length===Z.length&&$===Z)return"";var Y=$.length-1,z=-1;for(H=Z.length-1;H>=0;--H){var W=Z.charCodeAt(H);if(W===47){if(!K){X=H+1;break}}else{if(z===-1)K=!1,z=H+1;if(Y>=0)if(W===$.charCodeAt(Y)){if(--Y===-1)Q=H}else Y=-1,Q=z}}if(X===Q)Q=z;else if(Q===-1)Q=Z.length;return Z.slice(X,Q)}else{for(H=Z.length-1;H>=0;--H)if(Z.charCodeAt(H)===47){if(!K){X=H+1;break}}else if(Q===-1)K=!1,Q=H+1;if(Q===-1)return"";return Z.slice(X,Q)}}function e7(Z){B1(Z);var $=-1,X=0,Q=-1,K=!0,H=0;for(var Y=Z.length-1;Y>=0;--Y){var z=Z.charCodeAt(Y);if(z===47){if(!K){X=Y+1;break}continue}if(Q===-1)K=!1,Q=Y+1;if(z===46){if($===-1)$=Y;else if(H!==1)H=1}else if($!==-1)H=-1}if($===-1||Q===-1||H===0||H===1&&$===Q-1&&$===X+1)return"";return Z.slice($,Q)}function Z8(Z){if(Z===null||typeof Z!=="object")throw TypeError('The "pathObject" argument must be of type Object. Received type '+typeof Z);return r$("/",Z)}function $8(Z){B1(Z);var $={root:"",dir:"",base:"",ext:"",name:""};if(Z.length===0)return $;var X=Z.charCodeAt(0),Q=X===47,K;if(Q)$.root="/",K=1;else K=0;var H=-1,Y=0,z=-1,W=!0,G=Z.length-1,J=0;for(;G>=K;--G){if(X=Z.charCodeAt(G),X===47){if(!W){Y=G+1;break}continue}if(z===-1)W=!1,z=G+1;if(X===46){if(H===-1)H=G;else if(J!==1)J=1}else if(H!==-1)J=-1}if(H===-1||z===-1||J===0||J===1&&H===z-1&&H===Y+1){if(z!==-1)if(Y===0&&Q)$.base=$.name=Z.slice(1,z);else $.base=$.name=Z.slice(Y,z)}else{if(Y===0&&Q)$.name=Z.slice(1,H),$.base=Z.slice(1,z);else $.name=Z.slice(Y,H),$.base=Z.slice(Y,z);$.ext=Z.slice(H,z)}if(Y>0)$.dir=Z.slice(0,Y-1);else if(Q)$.dir="/";return $}var X8="/",Q8=":",K8,t$;var z6=V8(()=>{K8=((Z)=>(Z.posix=Z,Z))({resolve:I4,normalize:H6,isAbsolute:c7,join:o7,relative:s7,_makeLong:a7,dirname:r7,basename:t7,extname:e7,format:Z8,parse:$8,sep:X8,delimiter:Q8,win32:null,posix:null}),t$=K8});import*as l6 from"acorn";class d extends Error{line;column;source;filename;constructor(Z,$,X,Q){let K=`${Q||"<source>"}:${$.line}:${$.column}`;super(`${Z} at ${K}`);this.name="TranspileError",this.line=$.line,this.column=$.column,this.source=X,this.filename=Q}}class Q1 extends d{constructor(Z,$,X,Q){super(Z,$,X,Q);this.name="SyntaxError"}formatWithContext(Z=2){if(!this.source)return this.message;let $=this.source.split(`
|
|
2
2
|
`),X=this.line-1,Q=Math.max(0,X-Z),K=Math.min($.length-1,X+Z),H=[],Y=String(K+1).length;for(let z=Q;z<=K;z++){let W=String(z+1).padStart(Y),G=z===X?">":" ";if(H.push(`${G} ${W} | ${$[z]}`),z===X){let J=" ".repeat(Y+4+this.column);H.push(`${J}^ ${this.message.split(" at ")[0]}`)}}return H.join(`
|
|
3
3
|
`)}}class C8 extends d{expected;received;suggestion;constructor(Z,$,X){super(Z,$,X?.source,X?.filename);this.name="TypeError",this.expected=X?.expected,this.received=X?.received,this.suggestion=X?.suggestion}}function W1(Z){return{depth:Z.depth+1,locals:new Map,parent:Z,parameters:Z.parameters,atoms:Z.atoms,warnings:Z.warnings,source:Z.source,filename:Z.filename,options:Z.options}}function O8(Z,$){if($.locals.has(Z))return $.locals.get(Z);if($.parameters.has(Z))return $.parameters.get(Z)?.type;if($.parent)return O8(Z,$.parent);return}function l(Z){if(Z.loc)return{line:Z.loc.start.line,column:Z.loc.start.column};return{line:1,column:0}}function C0(Z,$){let X="",Q=0,K,H,Y="normal",z=[],W=[{type:"top-level",braceDepth:0}],G=0,J=()=>W[W.length-1]?.type||"top-level",U=()=>{let _=W[W.length-1];return _?.type==="class-body"&&G===_.braceDepth+1};while(Q<Z.length){let _=Z[Q],L=Z[Q+1];switch(Y){case"single-string":if(X+=_,_==="\\"&&Q+1<Z.length){X+=L,Q+=2;continue}if(_==="'")Y="normal";Q++;continue;case"double-string":if(X+=_,_==="\\"&&Q+1<Z.length){X+=L,Q+=2;continue}if(_==='"')Y="normal";Q++;continue;case"template-string":if(X+=_,_==="\\"&&Q+1<Z.length){X+=L,Q+=2;continue}if(_==="$"&&L==="{"){X+=L,Q+=2,z.push(1),Y="normal";continue}if(_==="`")Y="normal";Q++;continue;case"line-comment":if(X+=_,_===`
|
|
4
4
|
`)Y="normal";Q++;continue;case"block-comment":if(X+=_,_==="*"&&L==="/"){X+=L,Q+=2,Y="normal";continue}Q++;continue;case"regex":if(X+=_,_==="\\"&&Q+1<Z.length){X+=L,Q+=2;continue}if(_==="["){Q++;while(Q<Z.length&&Z[Q]!=="]")if(X+=Z[Q],Z[Q]==="\\"&&Q+1<Z.length)X+=Z[Q+1],Q+=2;else Q++;if(Q<Z.length)X+=Z[Q],Q++;continue}if(_==="/"){Q++;while(Q<Z.length&&/[gimsuy]/.test(Z[Q]))X+=Z[Q],Q++;Y="normal";continue}Q++;continue;case"normal":if(z.length>0){if(_==="{")z[z.length-1]++;else if(_==="}"){if(z[z.length-1]--,z[z.length-1]===0){z.pop(),X+=_,Q++,Y="template-string";continue}}}if(_==="'"){X+=_,Q++,Y="single-string";continue}if(_==='"'){X+=_,Q++,Y="double-string";continue}if(_==="`"){X+=_,Q++,Y="template-string";continue}if(_==="/"&&L==="/"){X+=_+L,Q+=2,Y="line-comment";continue}if(_==="/"&&L==="*"){X+=_+L,Q+=2,Y="block-comment";continue}if(_==="/"){let R=X.trimEnd();if(!R[R.length-1]||/[=(!,;:{[&|?+\-*%<>~^]$/.test(R)||/\b(return|case|throw|in|of|typeof|instanceof|new|delete|void)\s*$/.test(R)){X+=_,Q++,Y="regex";continue}}break}if(_==="{"){G++,X+=_,Q++;continue}if(_==="}"){G--;let R=W[W.length-1];if(R&&G===R.braceDepth)W.pop();X+=_,Q++;continue}let q=Z.slice(Q).match(/^class\s+\w+(?:\s+extends\s+\w+)?\s*\{/);if(q){let R=q[0].slice(0,-1);X+=R,Q+=R.length,W.push({type:"class-body",braceDepth:G});continue}let I=Z.slice(Q).match(/^function\s+(\w+)\s*\(/);if(I){let R=I[1],V=I[0].length,w=Z[Q+V],F=null,B=Q+V;if(w==="?"||w==="!")if(F=w,B++,F==="!")$.unsafeFunctions.add(R);else $.safeFunctions.add(R);X+=`function ${R}(`,Q=B;let P=j0(Z,Q,"(",")");if(!P){X+=Z[Q],Q++;continue}let{content:C,endPos:O}=P;Q=O;let T=P4(C,$,!0);X+=T+")";let S=Q;while(S<Z.length&&/\s/.test(Z[S]))S++;let g=Z.slice(S,S+2);if(g==="->"||g==="-?"||g==="-!"){S+=2;while(S<Z.length&&/\s/.test(Z[S]))S++;let m=F0(Z,S);if(m){let{type:a,endPos:v}=m;if(K===void 0){if(K=a,g==="-?")H="safe";else if(g==="-!")H="unsafe"}Q=v}}continue}let M=Z.slice(Q).match(/^(constructor|(?:get|set)\s+\w+|async\s+\w+|\w+)\s*\(/);if(M&&U()){let R=M[1],V=M[0].length,w=Q+V;X+=R+"(",Q=w;let F=j0(Z,Q,"(",")");if(!F){X+=Z[Q],Q++;continue}let{content:B,endPos:P}=F;Q=P;let C=P4(B,$,!0);X+=C+")";let O=Q;while(O<Z.length&&/\s/.test(Z[O]))O++;let T=Z.slice(O,O+2);if(T==="->"||T==="-!"||T==="-?"){O+=2;while(O<Z.length&&/\s/.test(Z[O]))O++;let S=F0(Z,O);if(S)Q=S.endPos}else if(Z[O]===":"){O++;while(O<Z.length&&/\s/.test(Z[O]))O++;let S=F0(Z,O);if(S)Q=S.endPos}continue}if(Z[Q]==="("){let R=j0(Z,Q+1,"(",")");if(!R){X+=Z[Q],Q++;continue}let{content:V,endPos:w}=R,F=w;while(F<Z.length&&/\s/.test(Z[F]))F++;let B,P=Z.slice(F,F+2);if(P==="->"||P==="-?"||P==="-!"){F+=2;while(F<Z.length&&/\s/.test(Z[F]))F++;let C=F0(Z,F);if(C){B=C.type,F=C.endPos;while(F<Z.length&&/\s/.test(Z[F]))F++}}if(Z.slice(F,F+2)==="=>"){let C=null,O=V,T=V.trimStart();if(T.startsWith("?")&&(T.length===1||/\s/.test(T[1])))C="?",O=T.slice(1);else if(T.startsWith("!")&&(T.length===1||/\s/.test(T[1])))C="!",O=T.slice(1);let S=P4(O,$,!1);X+=`(${C==="?"?"/* safe */ ":C==="!"?"/* unsafe */ ":""}${S})`,Q=w;while(Q<F&&/\s/.test(Z[Q]))X+=Z[Q],Q++;if(B)Q=F}else{let C=C0(V,$);X+=`(${C.source})`,Q=w}continue}X+=Z[Q],Q++}return{source:X,returnType:K,returnSafety:H}}function j0(Z,$,X,Q){let K=1,H=$,Y=!1,z="";while(H<Z.length&&K>0){let W=Z[H];if(!Y&&(W==="'"||W==='"'||W==="`"))Y=!0,z=W;else if(Y&&W===z&&Z[H-1]!=="\\")Y=!1;else if(!Y){if(W===X)K++;else if(W===Q)K--}H++}if(K!==0)return null;return{content:Z.slice($,H-1),endPos:H}}function w6(Z,$){let X=$;while(X<Z.length&&/\s/.test(Z[X]))X++;if(X>=Z.length)return null;let Q=X,K=Z[X];if(K==="{"||K==="["){let Y=K==="{"?"}":"]",z=j0(Z,X+1,K,Y);if(!z)return null;return{value:Z.slice(Q,z.endPos),endPos:z.endPos}}if(K==="'"||K==='"'||K==="`"){X++;while(X<Z.length){if(Z[X]===K&&Z[X-1]!=="\\")return X++,{value:Z.slice(Q,X),endPos:X};X++}return null}if(/[-+\d]/.test(K)){while(X<Z.length&&/[\d.eE+-]/.test(Z[X]))X++;return{value:Z.slice(Q,X),endPos:X}}let H=Z.slice(X).match(/^(true|false|null|undefined)\b/);if(H)return{value:H[1],endPos:X+H[1].length};return null}function t1(Z){return Z.replace(/(?<!\|)\|(?!\|)/g," || ")}function F0(Z,$){let X=$,Q=0,K=!1,H="",Y=!1,z=(W)=>({type:t1(Z.slice($,W).trim()),endPos:W});while(X<Z.length){let W=Z[X];if(!K&&(W==="'"||W==='"'||W==="`")){K=!0,H=W,Y=!0,X++;continue}if(K){if(W===H&&Z[X-1]!=="\\"){if(K=!1,X++,Q===0){let G=X;while(G<Z.length&&/\s/.test(Z[G]))G++;if(Z[G]==="{"){if(!Z.slice(G+1).match(/^\s*(\w+)\s*:/))return z(X)}if(Z[G]!=="|"&&Z[G]!=="&")return z(X)}continue}X++;continue}if(W==="{"||W==="["||W==="("){Q++,Y=!0,X++;continue}if(W==="}"||W==="]"||W===")"){if(Q--,Q===0){X++;let G=X;while(G<Z.length&&/\s/.test(Z[G]))G++;if(Z[G]==="|"||Z[G]==="&")continue;return z(X)}X++;continue}if(Q===0&&W==="{"){if(Y)return z(X);if(Z.slice(X+1).match(/^\s*(\w+)\s*:/)){Q++,Y=!0,X++;continue}return z(X)}if(Q===0&&(W==="|"||W==="&")){if(X++,X<Z.length&&Z[X]==="|")X++;while(X<Z.length&&/\s/.test(Z[X]))X++;continue}if(Q===0&&(/\d/.test(W)||W==="-"&&/\d/.test(Z[X+1]))){let G=X;if(Z[G]==="-")G++;while(G<Z.length&&/\d/.test(Z[G]))G++;if(G<Z.length&&Z[G]==="."&&/\d/.test(Z[G+1])){G++;while(G<Z.length&&/\d/.test(Z[G]))G++}if(G<Z.length&&(Z[G]==="e"||Z[G]==="E")){if(G++,G<Z.length&&(Z[G]==="+"||Z[G]==="-"))G++;while(G<Z.length&&/\d/.test(Z[G]))G++}Y=!0,X=G;while(X<Z.length&&/\s/.test(Z[X]))X++;if(X<Z.length&&Z[X]==="{")return{type:t1(Z.slice($,G).trim()),endPos:G};if(Z[X]!=="|"&&Z[X]!=="&")return{type:t1(Z.slice($,G).trim()),endPos:G};continue}if(Q===0&&/[a-zA-Z_]/.test(W)){let G=X;while(G<Z.length&&/\w/.test(Z[G]))G++;Y=!0,X=G;while(X<Z.length&&/\s/.test(Z[X]))X++;if(X<Z.length&&Z[X]==="{"){if(!Z.slice(X+1).match(/^\s*(\w+)\s*:/)){let U=G;while(U>$&&/\s/.test(Z[U-1]))U--;return{type:t1(Z.slice($,U).trim()),endPos:G}}}if(Z[X]!=="|"&&Z[X]!=="&")return{type:t1(Z.slice($,G).trim()),endPos:G};continue}X++}if(Y)return z(X);return null}function O0(Z){let $=[],X="",Q=0,K=!1,H=!1,Y=0;while(Y<Z.length){let z=Z[Y],W=Z[Y+1];if(!H&&z==="/"&&W==="/"){K=!0,X+="//",Y+=2;continue}if(!K&&z==="/"&&W==="*"){H=!0,X+="/*",Y+=2;continue}if(K&&z===`
|
|
@@ -190,11 +190,10 @@ ${H}}`}return String(Z)}function HZ(Z){let $=Z.replace(/\/\*[\s\S]*?\*\//g,(X)=>
|
|
|
190
190
|
const __expected = ${JSON.stringify(w.expected)};${w.defaults?`
|
|
191
191
|
const __defaults = ${JSON.stringify(w.defaults)};
|
|
192
192
|
if (typeof __actual === 'object' && __actual !== null) __actual = Object.assign({}, __defaults, __actual);`:""}
|
|
193
|
-
|
|
194
|
-
if (__typeResult.matches) {
|
|
193
|
+
if (__deepEqual(__actual, __expected)) {
|
|
195
194
|
__sigTestResults.push({ idx: ${F}, passed: true });
|
|
196
195
|
} else {
|
|
197
|
-
__sigTestResults.push({ idx: ${F}, passed: false, error:
|
|
196
|
+
__sigTestResults.push({ idx: ${F}, passed: false, error: 'Expected ' + __format(__expected) + ' at \\'${w.funcName}\\', got ' + __format(__actual) });
|
|
198
197
|
}
|
|
199
198
|
} catch (e) {
|
|
200
199
|
__sigTestResults.push({ idx: ${F}, passed: false, error: e.message || String(e) });
|
|
@@ -414,4 +413,4 @@ ${K.signature}
|
|
|
414
413
|
Supported: comparisons, &&, ||, !, arithmetic, member access (a.b), literals`)}return Q.node}function x$(Z){let $=[],X=0;while(X<Z.length){while(X<Z.length&&/\s/.test(Z[X]))X++;if(X>=Z.length)break;if(Z[X]==='"'||Z[X]==="'"){let Q=Z[X++],K="";while(X<Z.length&&Z[X]!==Q)if(Z[X]==="\\"&&X+1<Z.length)X++,K+=Z[X++];else K+=Z[X++];X++,$.push(JSON.stringify(K));continue}if(Z.slice(X,X+2).match(/^(&&|\|\||==|!=|>=|<=)$/)){$.push(Z.slice(X,X+2)),X+=2;continue}if("+-*/%><!().?:[]".includes(Z[X])){$.push(Z[X]),X++;continue}if(/\d/.test(Z[X])){let Q="";while(X<Z.length&&/[\d.]/.test(Z[X]))Q+=Z[X++];$.push(Q);continue}if(/[a-zA-Z_]/.test(Z[X])){let Q="";while(X<Z.length&&/[a-zA-Z0-9_]/.test(Z[X]))Q+=Z[X++];$.push(Q);continue}X++}return $}function f7(Z,$,X){return u$(Z,$,X)}function u$(Z,$,X){let{node:Q,pos:K}=k7(Z,$,X);while(Z[K]==="||"){K++;let{node:H,pos:Y}=k7(Z,K,X);Q={$expr:"logical",op:"||",left:Q,right:H},K=Y}return{node:Q,pos:K}}function k7(Z,$,X){let{node:Q,pos:K}=g7(Z,$,X);while(Z[K]==="&&"){K++;let{node:H,pos:Y}=g7(Z,K,X);Q={$expr:"logical",op:"&&",left:Q,right:H},K=Y}return{node:Q,pos:K}}function g7(Z,$,X){let{node:Q,pos:K}=b7(Z,$,X),H=["==","!=",">","<",">=","<="];while(H.includes(Z[K])){let Y=Z[K++],{node:z,pos:W}=b7(Z,K,X);Q={$expr:"binary",op:Y,left:Q,right:z},K=W}return{node:Q,pos:K}}function b7(Z,$,X){let{node:Q,pos:K}=v7(Z,$,X);while(Z[K]==="+"||Z[K]==="-"){let H=Z[K++],{node:Y,pos:z}=v7(Z,K,X);Q={$expr:"binary",op:H,left:Q,right:Y},K=z}return{node:Q,pos:K}}function v7(Z,$,X){let{node:Q,pos:K}=X6(Z,$,X);while(Z[K]==="*"||Z[K]==="/"||Z[K]==="%"){let H=Z[K++],{node:Y,pos:z}=X6(Z,K,X);Q={$expr:"binary",op:H,left:Q,right:Y},K=z}return{node:Q,pos:K}}function X6(Z,$,X){if(Z[$]==="!"||Z[$]==="-"){let Q=Z[$++],{node:K,pos:H}=X6(Z,$,X);return{node:{$expr:"unary",op:Q,argument:K},pos:H}}return d$(Z,$,X)}function d$(Z,$,X){let Q=Z[$];if(Q==="("){let{node:K,pos:H}=f7(Z,$+1,X);return{node:K,pos:H+1}}if(Q&&Q.startsWith('"'))return{node:{$expr:"literal",value:JSON.parse(Q)},pos:$+1};if(Q&&/^\d/.test(Q))return{node:{$expr:"literal",value:parseFloat(Q)},pos:$+1};if(Q==="true")return{node:{$expr:"literal",value:!0},pos:$+1};if(Q==="false")return{node:{$expr:"literal",value:!1},pos:$+1};if(Q==="null")return{node:{$expr:"literal",value:null},pos:$+1};if(Q&&/^[a-zA-Z_]/.test(Q)){let K={$expr:"ident",name:Q},H=$+1;while(Z[H]==="."){H++;let Y=Z[H++];K={$expr:"member",object:K,property:Y}}return{node:K,pos:H}}return{node:{$expr:"literal",value:null},pos:$+1}}class e{steps=[];atoms;proxy;constructor(Z){return this.atoms=Z,this.proxy=new Proxy(this,{get:($,X,Q)=>{if(X in $)return $[X];if(typeof X==="string"&&X in $.atoms)return(K)=>{let H=$.atoms[X];return $.add(H.create(K)),Q};return}}),this.proxy}add(Z){return this.steps.push(Z),this.proxy}as(Z){if(this.steps.length===0)throw Error("No step to capture");let $=this.steps[this.steps.length-1];return $.result=Z,this.proxy}step(Z){return this.add(Z)}return(Z){let $=this.atoms.return;if(!$)throw Error("Atom 'return' not found");let X=Z.schema??Z;return this.add($.create({schema:X}))}toJSON(){return{op:"seq",steps:[...this.steps]}}varsImport(Z){return this.add(this.atoms.varsImport.create({keys:Z}))}varsExport(Z){return this.add(this.atoms.varsExport.create({keys:Z}))}if(Z,$,X,Q){let K=new e(this.atoms);X(K);let H;if(Q){let W=new e(this.atoms);Q(W),H=W.steps}let Y=U4(Z,$),z=this.atoms.if;return this.add(z.create({condition:Y,then:K.steps,else:H}))}while(Z,$,X){let Q=new e(this.atoms);X(Q);let K=U4(Z,$),H=this.atoms.while;return this.add(H.create({condition:K,body:Q.steps}))}scope(Z){let $=new e(this.atoms);Z($);let X=this.atoms.scope;return this.add(X.create({steps:$.steps}))}map(Z,$,X){let Q=new e(this.atoms);X(Q);let K=this.atoms.map;return this.add(K.create({items:Z,as:$,steps:Q.steps}))}filter(Z,$,X,Q={}){let K=U4(X,Q),H=this.atoms.filter;return this.add(H.create({items:Z,as:$,condition:K}))}find(Z,$,X,Q={}){let K=U4(X,Q),H=this.atoms.find;return this.add(H.create({items:Z,as:$,condition:K}))}reduce(Z,$,X,Q,K){let H=new e(this.atoms);K(H);let Y=this.atoms.reduce;return this.add(Y.create({items:Z,as:$,accumulator:X,initial:Q,steps:H.steps}))}memoize(Z,$){let X=new e(this.atoms);Z(X);let Q=this.atoms.memoize;return this.add(Q.create({key:$,steps:X.steps}))}cache(Z,$,X){let Q=new e(this.atoms);Z(Q);let K=this.atoms.cache;return this.add(K.create({key:$,steps:Q.steps,ttlMs:X}))}try(Z){let $=new e(this.atoms);Z.try($);let X;if(Z.catch){let K=new e(this.atoms);Z.catch(K),X=K.steps}let Q=this.atoms.try;return this.add(Q.create({try:$.steps,catch:X}))}}var m$={take(Z){return new e(L4)},custom(Z){return new e(Z)},args(Z){return{$kind:"arg",path:Z}},val(Z){return Z}},RK=m$;import{validate as l$}from"tosijs-schema";function A0(Z,$={}){let{ast:X,returnType:Q,originalSource:K,requiredParams:H}=M1(Z,{filename:$.filename,colonShorthand:!0,vmTarget:!0}),Y=T0(X,$.filename),{ast:z,signature:W,warnings:G}=H0(Y,K,Q,$,H);return{ast:z,signature:W,warnings:G}}var i$=10;class Q6{atoms;constructor(Z={}){this.atoms={...L4,...Z}}get builder(){return new e(this.atoms)}get Agent(){return new e(this.atoms)}get A99(){return this.Agent}resolve(Z){return this.atoms[Z]}getTools(Z="all"){let $=Object.values(this.atoms);if(Array.isArray(Z))$=$.filter((X)=>Z.includes(X.op));else if(Z==="flow"){let X=["seq","if","while","return","try","varSet","varGet","scope"];$=$.filter((Q)=>X.includes(Q.op))}return $.map((X)=>({type:"function",function:{name:X.op,description:X.docs,parameters:X.inputSchema?.schema??{}}}))}async run(Z,$={},X={}){let Q;if(typeof Z==="string")if(e4(Z))Q=Z6(Z);else try{Q=A0(Z).ast}catch(L){throw Error(`AJS transpilation failed: ${L.message}`)}else Q=Z;let K=X.fuel??1000,H=X.timeoutMs??K*i$,Y=X.capabilities??{},z=[];if(!Y.store){let L=new Map,q=!1;Y.store={get:async(I)=>{if(!q)q=!0,z.push("Using default in-memory store (not suitable for production)");return L.get(I)},set:async(I,M)=>{if(!q)q=!0,z.push("Using default in-memory store (not suitable for production)");L.set(I,M)}}}let W=new AbortController,G=setTimeout(()=>W.abort(),H);if(X.signal)X.signal.addEventListener("abort",()=>W.abort());let J={fuel:{current:K},args:$,state:{},consts:new Set,capabilities:Y,resolver:(L)=>this.resolve(L),output:void 0,signal:W.signal,costOverrides:X.costOverrides,context:X.context,warnings:z};if(X.trace)J.trace=[];if(Q.op!=="seq")throw Error("Root AST must be 'seq'. Ensure you're passing a transpiled agent (use ajs`...` or transpile()).");let U=Q.inputSchema;if(U&&!l$($,U)){let L=new Y1("Input validation failed: args do not match expected schema","vm.run");return{result:L,error:L,fuelUsed:0,trace:J.trace,warnings:z.length>0?z:void 0}}try{await Promise.race([this.resolve("seq")?.exec(Q,J),new Promise((L,q)=>{if(W.signal.addEventListener("abort",()=>{q(Error(`Execution timeout after ${H}ms (fuel: ${K}). Consider increasing fuel or optimizing your agent.`))}),W.signal.aborted)q(Error(`Execution timeout after ${H}ms (fuel: ${K}). Consider increasing fuel or optimizing your agent.`))})])}catch(L){if(L.message?.includes("timeout")||L.message?.includes("aborted")||W.signal.aborted)J.error=new Y1(`Execution timeout after ${H}ms (fuel: ${K}). Consider increasing fuel or optimizing your agent.`,"vm.run");else throw L}finally{clearTimeout(G)}if(J.error&&J.output===void 0)J.output=J.error;let _=[...z,...J.warnings??[]];return{result:J.output,error:J.error,fuelUsed:K-J.fuel.current,trace:J.trace,warnings:_.length>0?_:void 0}}}var p$=null,y7=()=>p$??=new Q6;function x1(Z){if(!Z||typeof Z!=="object")return;if(Array.isArray(Z)){for(let $ of Z)x1($);return}if(Z.op==="return"&&"value"in Z)Z.value={__result:Z.value};if(Z.steps)x1(Z.steps);if(Z.then)x1(Z.then);if(Z.else)x1(Z.else);if(Z.body)x1(Z.body)}async function n$(Z){let{code:$,context:X={},fuel:Q=1000,timeoutMs:K,capabilities:H={}}=Z,Y=y7(),W=/\breturn\b/.test($)?`function __eval() { ${$} }`:`function __eval() { return (${$}) }`;try{let{ast:G}=A0(W);x1(G);let J=await Y.run(G,X,{fuel:Q,timeoutMs:K,capabilities:H}),U=J.result;return{result:U&&typeof U==="object"&&"__result"in U?U.__result:U,fuelUsed:J.fuelUsed,error:J.error?{message:J.error.message||String(J.error)}:void 0}}catch(G){return{result:void 0,fuelUsed:Q,error:{message:G.message||String(G)}}}}async function c$(Z){let{body:$,params:X=[],fuel:Q=1000,timeoutMs:K,capabilities:H={}}=Z,Y=y7(),W=`function __safeFn(${X.join(", ")}) { ${$} }`,{ast:G}=A0(W);return x1(G),async(...J)=>{let U={};for(let _=0;_<X.length;_++)U[X[_]]=J[_];try{let _=await Y.run(G,U,{fuel:Q,timeoutMs:K,capabilities:H}),L=_.result;return{result:L&&typeof L==="object"&&"__result"in L?L.__result:L,fuelUsed:_.fuelUsed,error:_.error?{message:_.error.message||String(_.error)}:void 0}}catch(_){return{result:void 0,fuelUsed:Q,error:{message:_.message||String(_)}}}}}function D4(Z,$={}){let{ast:X,returnType:Q,originalSource:K,requiredParams:H}=M1(Z,{filename:$.filename,colonShorthand:!0,vmTarget:!0}),Y=T0(X,$.filename),{ast:z,signature:W,warnings:G}=H0(Y,K,Q,$,H);return{ast:z,signature:W,warnings:G}}function fK(Z,...$){if(typeof Z==="string")return D4(Z).ast;let X=Z.reduce((Q,K,H)=>Q+K+($[H]!==void 0?String($[H]):""),"");return D4(X).ast}function hK(Z,$,...X){if(typeof Z==="string")return L0(Z,$);let Q=$!==void 0?[$,...X]:X,K=Z.reduce((H,Y,z)=>H+Y+(Q[z]!==void 0?String(Q[z]):""),"");return L0(K)}async function xK(Z,$={},X){let Q=X??await z4(),K=await Q.getTranspile(Z);if(K)return{ast:K.ast,signature:K.signature,warnings:K.warnings};let H=D4(Z,$);return Q.setTranspile(Z,{ast:H.ast,signature:H.signature,warnings:H.warnings}),H}async function uK(Z,$={},X){let Q=X??await z4(),K=await Q.getTJS(Z);if(K)return{code:K.code,types:K.types,metadata:K.types,testRunner:K.testRunner,testCount:K.testCount,warnings:K.warnings};let H=L0(Z,$);return Q.setTJS(Z,{code:H.code,types:H.types,testRunner:H.testRunner,testCount:H.testCount,warnings:H.warnings}),H}function dK(Z,$,X){let{ast:Q,signature:K}=D4(Z),H=async(Y)=>{return(await $.run(Q,Y,X)).result};return H.signature=K,H.ast=Q,H}function mK(Z){return Object.entries(Z).map(([$,X])=>{let Q=X.signature,K={},H=[];for(let[Y,z]of Object.entries(Q.parameters)){if(K[Y]=q4(z.type),z.description)K[Y].description=z.description;if(z.required)H.push(Y)}return{type:"function",function:{name:Q.name||$,description:Q.description,parameters:{type:"object",properties:K,required:H}}}})}function q4(Z){switch(Z.kind){case"string":return{type:"string"};case"number":return{type:"number"};case"boolean":return{type:"boolean"};case"null":return{type:"null"};case"array":return{type:"array",items:Z.items?q4(Z.items):{}};case"object":if(!Z.shape)return{type:"object"};return{type:"object",properties:Object.fromEntries(Object.entries(Z.shape).map(([$,X])=>[$,q4(X)]))};case"union":if(!Z.members)return{};return{anyOf:Z.members.map(q4)};case"any":default:return{}}}import{s as b}from"tosijs-schema";var h7=k("storeVectorize",b.object({text:b.string,model:b.string.optional}),b.array(b.number),async({text:Z},$)=>{let X=$.capabilities.vector;if(!X)throw Error("Capability 'vector' missing. Ensure vector battery is loaded.");let Q=N(Z,$);return X.embed(Q)},{docs:"Generate embeddings using vector battery",cost:20}),x7=k("storeCreateCollection",b.object({collection:b.string,dimension:b.number.optional}),void 0,async({collection:Z,dimension:$},X)=>{let Q=X.capabilities.store;if(!Q?.createCollection)throw Error("Capability 'store' missing or does not support createCollection.");let K=N(Z,X),H=N($,X);return Q.createCollection(K,void 0,H)},{docs:"Create a vector store collection",cost:5}),u7=k("storeVectorAdd",b.object({collection:b.string,doc:b.any}),void 0,async({collection:Z,doc:$},X)=>{let Q=X.capabilities.store;if(!Q?.vectorAdd)throw Error("Capability 'store' missing or does not support vectorAdd.");let K=N(Z,X),H=N($,X);return Q.vectorAdd(K,H)},{docs:"Add a document to a vector store collection",cost:5}),d7=k("storeSearch",b.object({collection:b.string,queryVector:b.array(b.number),k:b.number.optional,filter:b.record(b.any).optional}),b.array(b.any),async({collection:Z,queryVector:$,k:X,filter:Q},K)=>{let H=K.capabilities.store;if(!H?.vectorSearch)throw Error("Capability 'store' missing or does not support vectorSearch.");let Y=N(Z,K),z=N($,K),W=N(X,K)??5,G=N(Q,K);return H.vectorSearch(Y,z,W,G)},{docs:"Search vector store",cost:(Z,$)=>5+(N(Z.k,$)??5)}),m7=k("llmPredictBattery",b.object({system:b.string.optional,user:b.string,tools:b.array(b.any).optional,responseFormat:b.any.optional}),b.object({role:b.string.optional,content:b.string.optional,tool_calls:b.array(b.any).optional}),async({system:Z,user:$,tools:X,responseFormat:Q},K)=>{let H=K.capabilities.llmBattery;if(!H?.predict)throw Error("Capability 'llmBattery' missing or invalid.");let Y=N(Z,K)??"You are a helpful agent.",z=N($,K),W=N(X,K),G=N(Q,K);return H.predict(Y,z,W,G)},{docs:"Generate completion using LLM battery",cost:100}),l7=k("llmVision",b.object({system:b.string.optional,prompt:b.string,images:b.array(b.string),responseFormat:b.any.optional}),b.object({role:b.string.optional,content:b.string.optional,tool_calls:b.array(b.any).optional}),async({system:Z,prompt:$,images:X,responseFormat:Q},K)=>{let H=K.capabilities.llmBattery;if(!H?.predict)throw Error("Capability 'llmBattery' missing or invalid.");let Y=N(Z,K)??"You analyze images accurately and concisely.",z=N($,K),W=N(X,K)??[],G=N(Q,K);return H.predict(Y,{text:z,images:W},void 0,G)},{docs:"Analyze images using a vision model",timeoutMs:120000,cost:150});var JH={storeCreateCollection:x7,storeSearch:d7,storeVectorAdd:u7,storeVectorize:h7,llmPredictBattery:m7,llmVision:l7};var i7=new Map,A4=new Map;function o$(Z,$){if(Z.length!==$.length)throw Error("Vectors must have the same length for cosine similarity.");let X=0,Q=0,K=0;for(let H=0;H<Z.length;H++)X+=Z[H]*$[H],Q+=Z[H]*Z[H],K+=$[H]*$[H];if(Q=Math.sqrt(Q),K=Math.sqrt(K),Q===0||K===0)return 0;return X/(Q*K)}function K6(){return{async get(Z){return i7.get(Z)},async set(Z,$){i7.set(Z,$)},async createCollection(Z,$,X){if(A4.has(Z))console.warn(`Collection '${Z}' already exists. Overwriting.`);A4.set(Z,[])},async vectorAdd(Z,$){let X=A4.get(Z);if(!X)throw Error(`Collection '${Z}' not found. Create it first.`);if(!$.embedding||!Array.isArray($.embedding))throw Error("Document must have an 'embedding' property that is an array of numbers.");X.push($)},async vectorSearch(Z,$,X=5){let Q=A4.get(Z);if(!Q)throw Error(`Collection '${Z}' not found. Create it first.`);let K=Q.map((H)=>({doc:H,score:o$($,H.embedding)}));return K.sort((H,Y)=>Y.score-H.score),K.slice(0,X).map((H)=>H.doc)}}}function s$(Z){if(typeof Z==="string")return{role:"user",content:Z};let $=[{type:"text",text:Z.text}];for(let X of Z.images||[])$.push({type:"image_url",image_url:{url:X}});return{role:"user",content:$}}var a$="http://localhost:1234/v1";function p7(Z,$=a$){return{async predict(X,Q,K,H){try{let Y=H?Z.getStructuredLLM():Z.getLLM(),z=[{role:"system",content:X},s$(Q)],W=await fetch(`${$}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:Y.id,messages:z,temperature:0.7,tools:K,response_format:H})});if(!W.ok)throw Error(`LLM Error: ${W.status} ${W.statusText}`);return(await W.json()).choices[0]?.message??{content:""}}catch(Y){if(Y.cause?.code==="ECONNREFUSED")throw Error("No LLM provider configured. Please start LM Studio or provide an API key.");throw Y}},async embed(X){try{let Q=Z.getEmbedding(),K=await fetch(`${$}/embeddings`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:Q.id,input:X})});if(!K.ok)throw Error(`Embedding Error: ${K.status}`);return(await K.json()).data[0]?.embedding??[]}catch(Q){if(Q.cause?.code==="ECONNREFUSED")throw Error("No LLM provider configured. Please start LM Studio or provide an API key.");throw Q}}}}var I0=typeof window<"u"&&typeof window.localStorage<"u";async function e$(Z){try{if(I0){let $=window.localStorage.getItem(".models.cache.json");if(!$)return null;let X=JSON.parse($);if(X.baseUrl!==Z)return null;if(Date.now()-X.timestamp>86400000)return null;return X.models}else{let $=await import("node:fs/promises"),Q=(await Promise.resolve().then(() => (z6(),Y6))).join(process.cwd(),".models.cache.json");try{let K=await $.readFile(Q,"utf-8"),H=JSON.parse(K);if(H.baseUrl!==Z)return null;if(Date.now()-H.timestamp>86400000)return null;return H.models}catch{return null}}}catch($){return console.warn("⚠️ Error reading model cache:",$),null}}async function ZX(Z,$){let X={timestamp:Date.now(),baseUrl:Z,models:$};try{if(I0)window.localStorage.setItem(".models.cache.json",JSON.stringify(X));else{let Q=await import("node:fs/promises"),H=(await Promise.resolve().then(() => (z6(),Y6))).join(process.cwd(),".models.cache.json");await Q.writeFile(H,JSON.stringify(X,null,2))}}catch(Q){console.error("❌ Error writing model cache:",Q)}}var R0=async(Z,$)=>{let X=new AbortController,Q=setTimeout(()=>X.abort(),60000);try{let K=await fetch(Z,{...$,signal:X.signal});return clearTimeout(Q),K}catch(K){throw clearTimeout(Q),K}};async function $X(Z,$){try{let X={type:"json_schema",json_schema:{name:"test",strict:!1,schema:{type:"object",properties:{status:{type:"string"}}}}},Q=await R0(`${Z}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:$,messages:[{role:"system",content:"You respond in JSON."},{role:"user",content:'Return JSON: {"status": "ok"}'}],response_format:X,max_tokens:20})});if(!Q.ok){if(Q.status===400)return XX(Z,$);return{ok:!1,msg:`HTTP ${Q.status}`}}let K=await Q.json();return JSON.parse(K.choices[0].message.content),{ok:!0,msg:"OK (Schema)"}}catch(X){return{ok:!1,msg:X.message||"Error"}}}async function XX(Z,$){try{if((await R0(`${Z}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:$,messages:[{role:"user",content:'JSON: {"a":1}'}],response_format:{type:"json_object"},max_tokens:10})})).ok)return{ok:!0,msg:"OK (Legacy Mode)"};return{ok:!1,msg:"Not Supported"}}catch{return{ok:!1,msg:"Legacy Fail"}}}async function QX(Z,$){try{return(await R0(`${Z}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:$,messages:[{role:"user",content:"hi"}],max_tokens:1})})).ok}catch{return!1}}async function KX(Z,$){try{let X=await R0(`${Z}/embeddings`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:$,input:"test"})});if(!X.ok)return null;return(await X.json()).data[0]?.embedding?.length??null}catch{return null}}var HX="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg==";async function YX(Z,$){try{return(await R0(`${Z}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:$,messages:[{role:"user",content:[{type:"text",text:"What color is this?"},{type:"image_url",image_url:{url:HX}}]}],max_tokens:10})})).ok}catch{return!1}}async function H8(Z){let $=await e$(Z),X=[];try{let Y=await fetch(`${Z}/models`);if(!Y.ok)throw Error("Could not connect");X=(await Y.json()).data.map((W)=>W.id).sort()}catch(Y){if($)return console.log("⚠️ LM Studio unavailable, using cached model audit."),$;return console.error("❌ Failed to connect to LM Studio."),[]}if($){let Y=$.map((z)=>z.id).sort();if(JSON.stringify(X)===JSON.stringify(Y))return console.log("✅ Using cached model audit."),$;console.log("\uD83D\uDD0D Model list changed. Re-running audit...")}console.log("\uD83D\uDD0D Scanning models (this may take a moment)...");let Q=[],K=X.map((Y)=>({id:Y})),H;if(!I0)H=await import("node:readline");for(let Y of K){if(!I0&&H)H.cursorTo(process.stdout,0),process.stdout.write(`\uD83D\uDC49 Testing: ${Y.id}...`),H.clearLine(process.stdout,1);let z="Unknown",W=!1,G=!1,J="",U=void 0,_=await QX(Z,Y.id),L=await KX(Z,Y.id);if(L)U=L;if(_){z="LLM";let q=await $X(Z,Y.id);if(W=q.ok,G=await YX(Z,Y.id),J=W?q.msg:`Fail: ${q.msg}`,G)J+=" +Vision"}else if(L)z="Embedding",J=`OK (Dim: ${L})`;else J="LLM Fail";Q.push({id:Y.id,type:z,structuredOutput:W,vision:G,dimension:U,status:J})}if(!I0&&H)H.cursorTo(process.stdout,0),H.clearLine(process.stdout,0);return console.log(`
|
|
415
414
|
`),console.table(Q),await ZX(Z,Q),console.log("\uD83D\uDCDD Audit results saved to cache."),Q}var zX="http://localhost:1234/v1";class W6{baseUrl;models=[];defaultLLM=null;defaultEmbedding=null;defaultStructuredLLM=null;constructor(Z=zX){this.baseUrl=Z}async audit(){this.models=await H8(this.baseUrl),this.selectDefaults()}selectDefaults(){if(this.defaultEmbedding=this.models.find((Z)=>Z.type==="Embedding")||null,this.defaultLLM=this.models.find((Z)=>Z.type==="LLM")||null,this.defaultStructuredLLM=this.models.find((Z)=>Z.type==="LLM"&&Z.structuredOutput)||null,!this.defaultEmbedding)console.warn("⚠️ No embedding model found.");if(!this.defaultLLM)console.warn("⚠️ No LLM found.");if(!this.defaultStructuredLLM)console.warn("⚠️ No LLM with structured output support found.")}getModels(){return this.models}_setDefaultModel(Z,$,X,Q){let K=this.models.find((H)=>H.id===Z&&X(H));if(!K)throw Error(`Model '${Z}' not found or is not ${Q}.`);this[$]=K}setDefaultLLM(Z){this._setDefaultModel(Z,"defaultLLM",($)=>$.type==="LLM","an LLM")}setDefaultEmbedding(Z){this._setDefaultModel(Z,"defaultEmbedding",($)=>$.dimension!==void 0,"an embedding model")}setDefaultStructuredLLM(Z){this._setDefaultModel(Z,"defaultStructuredLLM",($)=>$.type==="LLM"&&$.structuredOutput,"a structured-output LLM")}getLLM(){if(!this.defaultLLM)throw Error("No LLM available.");return this.defaultLLM}getEmbedding(){if(!this.defaultEmbedding)throw Error("No embedding model available.");return this.defaultEmbedding}getStructuredLLM(){if(!this.defaultStructuredLLM)throw Error("No structured-output LLM available.");return this.defaultStructuredLLM}}var WX=typeof window<"u",GX=WX&&window.location.protocol==="https:",B0=null,G6=null,Y8=!1;async function JX(){if(Y8)return{localModels:B0,llm:G6};if(Y8=!0,GX)return console.log("\uD83D\uDCE1 HTTPS detected - local LLM endpoints disabled. Use HTTP for local LLM support."),{localModels:null,llm:null};try{B0=new W6,await B0.audit(),G6=p7(B0)}catch(Z){console.warn("⚠️ Could not connect to local LLM:",Z)}return{localModels:B0,llm:G6}}async function _X(){let{localModels:Z,llm:$}=await JX();return{vector:$?{embed:$.embed}:void 0,store:K6(),llmBattery:$,models:Z}}async function MH(){return _X()}var wH={store:K6(),llmBattery:null,vector:void 0,models:null};function LX(Z){if(typeof Z!=="string")return!1;let $=new Date(Z);return!isNaN($.getTime())&&Z.includes("T")}function UX(){return new Date().toISOString()}function s1(Z,$,X,Q=0,K=0,H=0,Y=0){return new Date(Date.UTC(Z,$-1,X,Q,K,H,Y)).toISOString()}function z8(Z){let $=new Date(Z);if(isNaN($.getTime()))throw Error(`Invalid date string: ${Z}`);return $.toISOString()}function qX(Z){try{return z8(Z)}catch{return null}}function M0(Z,$){let X=new Date(Z);return X.setTime(X.getTime()+$),X.toISOString()}function DX(Z,$){return M0(Z,$*1000)}function AX(Z,$){return M0(Z,$*60*1000)}function IX(Z,$){return M0(Z,$*60*60*1000)}function W8(Z,$){return M0(Z,$*24*60*60*1000)}function RX(Z,$){return W8(Z,$*7)}function BX(Z,$){let X=new Date(Z),Q=X.getUTCMonth()+$;if(X.setUTCMonth(Q),X.getUTCMonth()!==(Q%12+12)%12)X.setUTCDate(0);return X.toISOString()}function MX(Z,$){let X=new Date(Z),Q=X.getUTCDate();if(X.setUTCFullYear(X.getUTCFullYear()+$),X.getUTCDate()!==Q)X.setUTCDate(0);return X.toISOString()}function N1(Z,$){return new Date(Z).getTime()-new Date($).getTime()}function wX(Z,$){return Math.floor(N1(Z,$)/1000)}function FX(Z,$){return Math.floor(N1(Z,$)/60000)}function jX(Z,$){return Math.floor(N1(Z,$)/3600000)}function PX(Z,$){return Math.floor(N1(Z,$)/86400000)}function a1(Z){return new Date(Z).getUTCFullYear()}function R4(Z){return new Date(Z).getUTCMonth()+1}function J6(Z){return new Date(Z).getUTCDate()}function VX(Z){return new Date(Z).getUTCHours()}function CX(Z){return new Date(Z).getUTCMinutes()}function OX(Z){return new Date(Z).getUTCSeconds()}function NX(Z){return new Date(Z).getUTCMilliseconds()}function EX(Z){let $=new Date(Z).getUTCDay();return $===0?7:$}function B4(Z,$,X){let Q=new Date(Z),K={timeZone:$,...X};return new Intl.DateTimeFormat(void 0,K).format(Q)}function TX(Z,$){return B4(Z,$,{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"})}function SX(Z,$){return B4(Z,$,{year:"numeric",month:"short",day:"numeric"})}function kX(Z,$){return B4(Z,$,{hour:"2-digit",minute:"2-digit",second:"2-digit"})}function gX(Z){return Z.slice(0,10)}function G8(Z,$){return N1(Z,$)<0}function J8(Z,$){return N1(Z,$)>0}function bX(Z,$){return N1(Z,$)===0}function vX(Z,$){return G8(Z,$)?Z:$}function fX(Z,$){return J8(Z,$)?Z:$}function yX(Z){return s1(a1(Z),R4(Z),J6(Z))}function hX(Z){return s1(a1(Z),R4(Z),J6(Z),23,59,59,999)}function xX(Z){return s1(a1(Z),R4(Z),1)}function uX(Z){let $=new Date(Z);return $.setUTCMonth($.getUTCMonth()+1,0),$.setUTCHours(23,59,59,999),$.toISOString()}function dX(Z){return s1(a1(Z),1,1)}function mX(Z){return s1(a1(Z),12,31,23,59,59,999)}var r1={isValid:LX,now:UX,from:s1,parse:z8,tryParse:qX,addMilliseconds:M0,addSeconds:DX,addMinutes:AX,addHours:IX,addDays:W8,addWeeks:RX,addMonths:BX,addYears:MX,diff:N1,diffSeconds:wX,diffMinutes:FX,diffHours:jX,diffDays:PX,year:a1,month:R4,day:J6,hour:VX,minute:CX,second:OX,millisecond:NX,dayOfWeek:EX,toLocal:B4,format:TX,formatDate:SX,formatTime:kX,toDate:gX,isBefore:G8,isAfter:J8,isEqual:bX,min:vX,max:fX,startOfDay:yX,endOfDay:hX,startOfMonth:xX,endOfMonth:uX,startOfYear:dX,endOfYear:mX};function _6(Z){if(typeof Z!=="string")return!1;if(!/^\d{4}-\d{2}-\d{2}$/.test(Z))return!1;let $=parseInt(Z.slice(0,4),10),X=parseInt(Z.slice(5,7),10),Q=parseInt(Z.slice(8,10),10);if(X<1||X>12)return!1;if(Q<1)return!1;let K=[31,28,31,30,31,30,31,31,30,31,30,31],H=X===2&&($%4===0&&$%100!==0||$%400===0)?29:K[X-1];return Q<=H}function lX(){return r1.toDate(r1.now())}function iX(Z){let $=new Date;return new Intl.DateTimeFormat("en-CA",{timeZone:Z,year:"numeric",month:"2-digit",day:"2-digit"}).format($)}function _1(Z,$,X){let Q=String(Z).padStart(4,"0"),K=String($).padStart(2,"0"),H=String(X).padStart(2,"0"),Y=`${Q}-${K}-${H}`;if(!_6(Y))throw Error(`Invalid date: ${Z}-${$}-${X}`);return Y}function _8(Z){if(/^\d{4}-\d{2}-\d{2}$/.test(Z)){if(!_6(Z))throw Error(`Invalid date: ${Z}`);return Z}let $=new Date(Z);if(isNaN($.getTime()))throw Error(`Invalid date string: ${Z}`);let X=$.getUTCFullYear(),Q=$.getUTCMonth()+1,K=$.getUTCDate();return _1(X,Q,K)}function pX(Z){try{return _8(Z)}catch{return null}}function M4(Z,$){let X=U8(Z);return r1.toDate(r1.addDays(X,$))}function nX(Z,$){return M4(Z,$*7)}function cX(Z,$){let X=X1(Z),Q=E1(Z),K=L6(Z),H=X*12+(Q-1)+$,Y=Math.floor(H/12),z=H%12+1,W=w0(Y,z),G=Math.min(K,W);return _1(Y,z,G)}function oX(Z,$){let X=X1(Z),Q=E1(Z),K=L6(Z),H=X+$,Y=w0(H,Q),z=Math.min(K,Y);return _1(H,Q,z)}function L8(Z,$){let Q=new Date(Z+"T00:00:00Z").getTime(),K=new Date($+"T00:00:00Z").getTime();return Math.round((Q-K)/86400000)}function sX(Z,$){let X=X1(Z),Q=E1(Z),K=X1($),H=E1($);return(X-K)*12+(Q-H)}function aX(Z,$){return X1(Z)-X1($)}function X1(Z){return parseInt(Z.slice(0,4),10)}function E1(Z){return parseInt(Z.slice(5,7),10)}function L6(Z){return parseInt(Z.slice(8,10),10)}function U6(Z){let $=new Date(Z+"T00:00:00Z").getUTCDay();return $===0?7:$}function rX(Z){let $=new Date(Z+"T00:00:00Z"),X=$.getUTCDay()||7;$.setUTCDate($.getUTCDate()+4-X);let Q=new Date(Date.UTC($.getUTCFullYear(),0,1));return Math.ceil((($.getTime()-Q.getTime())/86400000+1)/7)}function tX(Z){let $=_1(X1(Z),1,1);return L8(Z,$)+1}function q6(Z){return Math.ceil(E1(Z)/3)}function D6(Z){return Z%4===0&&Z%100!==0||Z%400===0}function w0(Z,$){let X=[31,28,31,30,31,30,31,31,30,31,30,31];if($===2&&D6(Z))return 29;return X[$-1]}function eX(Z){return D6(Z)?366:365}function U8(Z){return Z+"T00:00:00.000Z"}function ZQ(Z){return Math.floor(new Date(Z+"T00:00:00Z").getTime()/1000)}function $Q(Z){let $=new Date(Z*1000);return _1($.getUTCFullYear(),$.getUTCMonth()+1,$.getUTCDate())}function A6(Z,$){let X=new Date(Z+"T00:00:00Z"),Q={timeZone:"UTC",...$};return new Intl.DateTimeFormat(void 0,Q).format(X)}function XQ(Z){return A6(Z,{year:"numeric",month:"long",day:"numeric"})}function QQ(Z){return A6(Z,{year:"numeric",month:"short",day:"numeric"})}function KQ(Z,$){return Z<$}function HQ(Z,$){return Z>$}function YQ(Z,$){return Z===$}function zQ(Z,$){return Z<$?Z:$}function WQ(Z,$){return Z>$?Z:$}function GQ(Z,$,X){return Z>=$&&Z<=X}function JQ(Z){return _1(X1(Z),E1(Z),1)}function _Q(Z){let $=X1(Z),X=E1(Z);return _1($,X,w0($,X))}function LQ(Z){let X=(q6(Z)-1)*3+1;return _1(X1(Z),X,1)}function UQ(Z){let X=q6(Z)*3;return _1(X1(Z),X,w0(X1(Z),X))}function qQ(Z){return _1(X1(Z),1,1)}function DQ(Z){return _1(X1(Z),12,31)}function AQ(Z){let $=U6(Z);return M4(Z,-($-1))}function IQ(Z){let $=U6(Z);return M4(Z,7-$)}var RQ={isValid:_6,today:lX,todayIn:iX,from:_1,parse:_8,tryParse:pX,addDays:M4,addWeeks:nX,addMonths:cX,addYears:oX,diff:L8,diffMonths:sX,diffYears:aX,year:X1,month:E1,day:L6,dayOfWeek:U6,weekOfYear:rX,dayOfYear:tX,quarter:q6,isLeapYear:D6,daysInMonth:w0,daysInYear:eX,toTimestamp:U8,toUnix:ZQ,fromUnix:$Q,format:A6,formatLong:XQ,formatShort:QQ,isBefore:KQ,isAfter:HQ,isEqual:YQ,min:zQ,max:WQ,isBetween:GQ,startOfMonth:JQ,endOfMonth:_Q,startOfQuarter:LQ,endOfQuarter:UQ,startOfYear:qQ,endOfYear:DQ,startOfWeek:AQ,endOfWeek:IQ};export{C$ as xmlParse,c4 as wrap,l5 as whileLoop,B$ as vectorSearch,r5 as varsLet,a5 as varsImport,t5 as varsExport,c5 as varSet,s5 as varGet,n4 as validateArgs,T$ as uuid,C4 as typeToString,i1 as typeOf,m1 as typeDescriptorToTS,p5 as tryCatch,xK as transpileWithCache,L0 as transpileToJS,F$ as transpileCode,D4 as transpile,H0 as transformFunction,uK as tjsWithCache,hK as tjs,QZ as testUtils,W$ as template,g0 as stripTjsPreamble,k0 as stripModuleSyntax,I$ as storeSet,R$ as storeQuery,b$ as storeProcedure,A$ as storeGet,Y$ as split,V5 as setGlobalCache,J1 as seq,e5 as scope,b1 as runtime,j$ as runCode,i5 as ret,N as resolveValue,Z6 as resolveProcedureToken,v$ as releaseProcedure,Q7 as registerWasmBlock,G$ as regexMatch,X$ as reduce,E$ as random,K$ as push,o1 as procedureStore,E0 as preprocess,J$ as pick,i6 as parseReturnType,P1 as parseParameter,M1 as parse,_$ as omit,L$ as merge,O$ as memoize,Z$ as map,O8 as lookupVariable,M$ as llmPredict,N5 as lint,H$ as len,U$ as keys,V$ as jsonStringify,P$ as jsonParse,z$ as join,y4 as isValidUrl,h4 as isValidTimestamp,x4 as isValidLegalDate,C1 as isRuntimeType,e4 as isProcedureToken,w1 as isError,k5 as isAgentError,X7 as instantiateWasm,Y5 as installRuntime,K1 as inferTypeFromValue,m5 as iff,F5 as hashSourceSync,Y4 as hashSource,$6 as hash,mK as getToolDefinitions,K6 as getStoreCapabilityDefault,MH as getStandardCapabilities,l as getLocation,p7 as getLLMCapability,z4 as getGlobalCache,_X as getBatteries,S5 as generateDocsMarkdown,j7 as generateDocs,iZ as generateDTS,M5 as fromTS,Q$ as find,$$ as filter,D$ as fetch,N4 as extractTests,X0 as extractTDoc,A1 as extractLiteralValue,a6 as expectFunction,n as evaluateExpr,n5 as errorAtom,R1 as error,z5 as emitRuntimeWrapper,k as defineAtom,O1 as createChildScope,W1 as createChildContext,dK as createAgent,L4 as coreAtoms,o5 as constSet,k$ as consoleWarn,S$ as consoleLog,g$ as consoleError,NZ as compileWasmBlocks,f0 as compileToWasm,f$ as clearExpiredProcedures,v1 as checkType,N$ as cache,j1 as builtins,JH as batteryAtoms,wH as batteries,s6 as assertFunction,fK as ajs,w$ as agentRun,a0 as Union,e as TypedBuilder,C8 as TypeError,c as Type,d as TranspileError,u4 as TimestampType,r1 as Timestamp,c0 as TUuid,n0 as TUrl,x0 as TString,e0 as TRecord,l0 as TPositiveInt,t0 as TPair,u0 as TNumber,i0 as TNonEmptyString,$1 as TJS_VERSION,m0 as TInteger,p0 as TEmail,d0 as TBoolean,r0 as TArray,Q1 as SyntaxError,w5 as Schema,c$ as SafeFunction,t4 as PROCEDURE_TOKEN_PREFIX,s0 as Optional,o0 as Nullable,s4 as MetadataCache,W6 as LocalModels,d4 as LegalDateType,RQ as LegalDate,l1 as Generic,n$ as Eval,Z4 as Enum,g5 as DEFAULT_PROCEDURE_TTL,b5 as DEFAULT_MAX_AST_SIZE,Q6 as AgentVM,Y1 as AgentError,m$ as Agent,RK as A99};
|
|
416
415
|
|
|
417
|
-
//# debugId=
|
|
416
|
+
//# debugId=C3A7F0F260C81BE464756E2164756E21
|