tjs-lang 0.8.1 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +13 -4
- package/demo/autocomplete.test.ts +37 -0
- package/demo/docs.json +698 -8
- package/demo/examples.test.ts +6 -2
- package/demo/src/autocomplete.ts +40 -2
- package/demo/src/introspection-bridge.ts +140 -0
- package/demo/src/introspection-doc.test.ts +63 -0
- package/demo/src/playground-shared.ts +101 -16
- package/demo/src/playground-test-results.test.ts +112 -0
- package/demo/src/tjs-playground.ts +32 -5
- package/dist/examples/modules/dist/main.d.ts +34 -0
- package/dist/examples/modules/dist/math.d.ts +120 -0
- package/dist/index.js +115 -112
- package/dist/index.js.map +4 -4
- package/dist/src/lang/core.d.ts +1 -1
- package/dist/src/lang/dialect.d.ts +35 -0
- package/dist/src/lang/emitters/ast.d.ts +1 -1
- package/dist/src/lang/emitters/js-tests.d.ts +7 -0
- package/dist/src/lang/emitters/js.d.ts +12 -0
- package/dist/src/lang/index.d.ts +2 -1
- package/dist/src/lang/parser-types.d.ts +17 -0
- package/dist/src/lang/parser.d.ts +18 -0
- package/dist/src/lang/transpiler.d.ts +1 -0
- package/dist/src/lang/types.d.ts +18 -0
- package/dist/src/vm/runtime.d.ts +18 -0
- package/dist/src/vm/vm.d.ts +15 -1
- package/dist/tjs-batteries.js +2 -2
- package/dist/tjs-batteries.js.map +2 -2
- package/dist/tjs-eval.js +43 -43
- package/dist/tjs-eval.js.map +3 -3
- package/dist/tjs-from-ts.js +1 -1
- package/dist/tjs-from-ts.js.map +2 -2
- package/dist/tjs-lang.js +76 -73
- package/dist/tjs-lang.js.map +4 -4
- package/dist/tjs-vm.js +49 -49
- package/dist/tjs-vm.js.map +3 -3
- package/editors/codemirror/ajs-language.ts +130 -44
- package/editors/codemirror/completion-source.test.ts +114 -0
- package/editors/introspect-value.test.ts +61 -0
- package/editors/introspect-value.ts +86 -0
- package/editors/scope-symbols.test.ts +113 -0
- package/editors/scope-symbols.ts +173 -0
- package/llms.txt +1 -0
- package/package.json +21 -1
- package/src/batteries/audit.ts +3 -2
- package/src/cli/commands/check.ts +3 -2
- package/src/cli/commands/emit.ts +4 -2
- package/src/cli/commands/run.ts +6 -2
- package/src/cli/commands/types.ts +2 -2
- package/src/lang/codegen.test.ts +4 -1
- package/src/lang/core.ts +6 -4
- package/src/lang/dialect.test.ts +63 -0
- package/src/lang/dialect.ts +50 -0
- package/src/lang/emitters/ast.ts +145 -2
- package/src/lang/emitters/js-tests.ts +46 -37
- package/src/lang/emitters/js.ts +19 -2
- package/src/lang/features.test.ts +6 -5
- package/src/lang/index.ts +40 -5
- package/src/lang/parser-types.ts +17 -0
- package/src/lang/parser.test.ts +12 -6
- package/src/lang/parser.ts +113 -3
- package/src/lang/predicate-schema.test.ts +97 -0
- package/src/lang/predicate-schema.ts +168 -0
- package/src/lang/predicate.test.ts +184 -0
- package/src/lang/predicate.ts +550 -0
- package/src/lang/subset-invariant.test.ts +90 -0
- package/src/lang/suggest.test.ts +84 -0
- package/src/lang/transpiler.ts +34 -0
- package/src/lang/types.ts +18 -0
- package/src/lang/wasm.test.ts +8 -2
- package/src/linalg/linalg.test.ts +8 -2
- package/src/use-cases/batteries.test.ts +4 -0
- package/src/use-cases/local-helpers.test.ts +219 -0
- package/src/use-cases/timeout-overrides.test.ts +169 -0
- package/src/vm/atom-effects.test.ts +72 -0
- package/src/vm/atoms/batteries.ts +29 -3
- package/src/vm/runtime.ts +140 -4
- package/src/vm/vm.ts +47 -9
package/CLAUDE.md
CHANGED
|
@@ -86,6 +86,8 @@ bun run functions:serve # Local functions emulator
|
|
|
86
86
|
- `src/lang/inference.ts` - Type inference from example values
|
|
87
87
|
- `src/lang/json-schema.ts` - JSON Schema generation from TypeDescriptors and example values
|
|
88
88
|
- `src/lang/linter.ts` - Static analysis (unused vars, unreachable code, no-explicit-new)
|
|
89
|
+
- `src/lang/predicate.ts` - Predicate-safety verifier: certifies a cluster of pure, synchronous, composable predicates (reads the atom `effects` tag via `effectfulFromAtoms`); verified predicates compile to native JS. Also `suggest()` — mines a cluster for autocomplete completions (keyword sets → `value`s, `startsWith` guards → open-ended `stub`s like `var(--`; mined values run through the compiled predicate so they're guaranteed valid). Exported from `tjs-lang/lang`. See `experiments/predicates/` (CSS torture set + perf + suggest demo)
|
|
90
|
+
- `src/lang/predicate-schema.ts` - Predicate-aware JSON-Schema: the `$predicate` keyword (computational types). `compilePredicateSchema`/`validatePredicateSchema` — structure for naive validators, `$predicate` for aware ones (progressive enhancement). The serializable-into-JSON-Schema endgame; exported from `tjs-lang/lang`
|
|
89
91
|
- `src/lang/runtime.ts` - TJS runtime (monadic errors, type checking, wrapClass)
|
|
90
92
|
- `src/lang/wasm.ts` - WASM compiler (opcodes, disassembler, bytecode generation; multi-function module composition; wasm-to-wasm `call <index>` resolution)
|
|
91
93
|
- `src/lang/emitters/js-wasm.ts` - JS bootstrap emitter for compiled wasm modules (one `WebAssembly.compile` per file, name→export-index table, type-aware wrappers)
|
|
@@ -113,7 +115,11 @@ createAgent(source, vm) // Creates callable agent
|
|
|
113
115
|
|
|
114
116
|
// VM
|
|
115
117
|
const vm = new AgentVM(customAtoms)
|
|
116
|
-
await vm.run(ast, args, {
|
|
118
|
+
await vm.run(ast, args, {
|
|
119
|
+
fuel, capabilities, timeoutMs, trace,
|
|
120
|
+
costOverrides: { atomOp: 5 }, // per-atom fuel cost override
|
|
121
|
+
timeoutOverrides: { atomOp: 60_000 }, // per-atom wall-clock override (ms; 0 disables)
|
|
122
|
+
})
|
|
117
123
|
|
|
118
124
|
// Builder
|
|
119
125
|
Agent.take(schema).varSet(...).httpFetch(...).return(schema)
|
|
@@ -208,7 +214,7 @@ fn('a', 'b') // Returns { error: 'type mismatch', ... }
|
|
|
208
214
|
**Design Notes:**
|
|
209
215
|
|
|
210
216
|
- The two steps are intentionally separate for tree-shaking (TS support is optional)
|
|
211
|
-
- `fromTS` lives in a separate entry point (`
|
|
217
|
+
- `fromTS` lives in a separate entry point (`tjs-lang/lang/from-ts`)
|
|
212
218
|
- Import only what you need to keep bundle size minimal
|
|
213
219
|
- Each step is independently testable (see `src/lang/codegen.test.ts`)
|
|
214
220
|
- Constrained generics (`<T extends { id: number }>`) use the constraint as the example value instead of `any`
|
|
@@ -249,7 +255,7 @@ AJS expressions behave differently from JavaScript in several important ways:
|
|
|
249
255
|
- Unit tests alongside source files (`*.test.ts`)
|
|
250
256
|
- Integration tests in `src/use-cases/` (RAG, orchestration, malicious actors)
|
|
251
257
|
- Security tests in `src/use-cases/malicious-actor.test.ts`
|
|
252
|
-
- Language tests split across
|
|
258
|
+
- Language tests split across 18 files in `src/lang/` (lang.test.ts, features.test.ts, codegen.test.ts, parser.test.ts, from-ts.test.ts, wasm.test.ts, etc.)
|
|
253
259
|
- LLM integration tests (run via full `bun test`, skipped by `SKIP_LLM_TESTS`) need a local **LM Studio** server with a chat + embedding model loaded. Setup and the hard-won gotchas (model load failures, leaked-VRAM stray `node` worker, updating runtimes, CORS, the audit-cache parallel race) are in [`docs/lm-studio-setup.md`](docs/lm-studio-setup.md).
|
|
254
260
|
|
|
255
261
|
Coverage targets: 98% lines on `src/vm/runtime.ts` (security-critical), 80%+ overall.
|
|
@@ -260,7 +266,7 @@ Coverage targets: 98% lines on `src/vm/runtime.ts` (security-critical), 80%+ ove
|
|
|
260
266
|
|
|
261
267
|
### Adding a New Atom
|
|
262
268
|
|
|
263
|
-
1. Define with `defineAtom(opCode, inputSchema, outputSchema, implementation, { cost, timeoutMs, docs })`
|
|
269
|
+
1. Define with `defineAtom(opCode, inputSchema, outputSchema, implementation, { cost, timeoutMs, docs, effects })`
|
|
264
270
|
2. Add to `src/vm/atoms/` and export from `src/vm/atoms/index.ts`
|
|
265
271
|
3. Add tests
|
|
266
272
|
4. Run `bun run test:fast`
|
|
@@ -270,6 +276,7 @@ Coverage targets: 98% lines on `src/vm/runtime.ts` (security-critical), 80%+ ove
|
|
|
270
276
|
- `cost` can be static number or dynamic: `(input, ctx) => number`
|
|
271
277
|
- `timeoutMs` defaults to 1000ms; use `0` for no timeout (e.g., `seq`)
|
|
272
278
|
- Atoms are always async; fuel deduction is automatic in the `exec` wrapper
|
|
279
|
+
- `effects` defaults to `'pure'`; **set `'io'` for any atom that touches `ctx.capabilities` (fetch/store/llm/agent/code), is nondeterministic (random/uuid), or has side effects (console)**. This drives predicate-safety (a predicate may only call pure atoms — see `experiments/predicates/`). Core IO atoms are tagged centrally via `EFFECTFUL_CORE_OPS` in `runtime.ts`; the invariant is guarded by `src/vm/atom-effects.test.ts`.
|
|
273
280
|
|
|
274
281
|
### Debugging Agents
|
|
275
282
|
|
|
@@ -303,6 +310,7 @@ Full syntax documentation is in [`CLAUDE-TJS-SYNTAX.md`](CLAUDE-TJS-SYNTAX.md).
|
|
|
303
310
|
- **Return types**: `function add(a: 0, b: 0): 0 { ... }` (colon syntax, same as TypeScript)
|
|
304
311
|
- **Safety markers**: `!` = unsafe (skip validation), `?` = safe (explicit validation)
|
|
305
312
|
- **Mode defaults**: Native TJS has all modes ON by default (`TjsEquals`, `TjsClass`, `TjsDate`, `TjsNoeval`, `TjsNoVar`, `TjsStandard`). TS-originated code (`fromTS`) and AJS/VM code get modes OFF. `TjsCompat` directive explicitly disables all modes. `TjsStrict` enables all modes (useful for TS-originated code opting in).
|
|
313
|
+
- **Source dialect (`dialect: 'js' | 'tjs'`)**: the public, programmatic way to set the modes-on/off default. `tjs(src, { dialect: 'js' })` preserves plain-JS semantics (modes OFF, `safety: 'none'`); `'tjs'` (or a bare string) is native TJS (modes ON). `dialect` is authoritative; otherwise inferred from the `fromTS` annotation / `vmTarget`. For file-based tooling, use the canonical extension→dialect helpers `dialectForFilename(filename)` / `sourceKindForFilename(filename)` from `tjs-lang/lang` (`.js`/`.mjs`/`.cjs` → `'js'`, `.tjs` → `'tjs'`, `.ts` → use `fromTS`). This upholds the **TJS ⊇ JS** invariant — see `PRINCIPLES.md`. (`.tjs` is a _better_ language, not just JS; choosing it is the opt-in to the modes.)
|
|
306
314
|
- **Bang access**: `x!.foo` — returns MonadicError if `x` is null/undefined, otherwise bare `x.foo`. Chains propagate: `x!.foo!.bar`.
|
|
307
315
|
- **Type/Generic/FunctionPredicate**: Three declaration forms for runtime type predicates
|
|
308
316
|
- **`const!`**: Compile-time immutability, zero runtime cost
|
|
@@ -478,6 +486,7 @@ The CLI (`bun src/cli/tjs.ts run`) does NOT inject the test-block `expect` harne
|
|
|
478
486
|
|
|
479
487
|
### Additional Documentation
|
|
480
488
|
|
|
489
|
+
- `PRINCIPLES.md` — **non-negotiable language invariants**: options-off TJS ⊇ JS, and TJS ⊇ AJS. A richer layer may do _more_ with the same source but must never make subset-legal code _illegal_ (e.g. un-runnable signature tests are inconclusive, not errors). Read before changing parser/transpiler acceptance or signature-test behavior; a subset violation is a bug.
|
|
481
490
|
- `llms.txt` — agent-facing navigation index (ships in npm bundle); points to docs and source entry points
|
|
482
491
|
- `guides/footguns.md` — JS footguns TJS fixes (boxed-primitive truthiness, `==` coercion, `typeof null`, uninitialized `let`, etc.). Demo: `examples/js-footguns-fixed.tjs`.
|
|
483
492
|
- `guides/playground-imports.md` — how the playground/dev-server resolves bare imports: TFS service worker, default JSDelivr `/+esm` routing, esm.sh allowlist for peer-dep packages (React), CDN hints (`jsdelivr/`, `esmsh/`, `unpkg/`, `github/`), and full-URL passthrough.
|
|
@@ -40,6 +40,43 @@ describe('getCompletions', () => {
|
|
|
40
40
|
})
|
|
41
41
|
})
|
|
42
42
|
|
|
43
|
+
describe('destructured bindings (scope-aware)', () => {
|
|
44
|
+
// Regression: the old regex `const NAME =` extractor missed all
|
|
45
|
+
// destructuring, so the tosijs todo example suggested nothing.
|
|
46
|
+
const todo = `import { elements, tosi } from 'tosijs'
|
|
47
|
+
const { todoApp } = tosi({ todoApp: { items: [], newItem: '' } })
|
|
48
|
+
const { h1, ul, template, li, label, input, button } = elements
|
|
49
|
+
`
|
|
50
|
+
|
|
51
|
+
it('suggests destructured locals (todoApp, h1, button)', () => {
|
|
52
|
+
const completions = getCompletions({
|
|
53
|
+
source: todo,
|
|
54
|
+
position: todo.length,
|
|
55
|
+
})
|
|
56
|
+
const labels = completions.map((c) => c.label)
|
|
57
|
+
expect(labels).toContain('todoApp')
|
|
58
|
+
expect(labels).toContain('h1')
|
|
59
|
+
expect(labels).toContain('button')
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('shows where a destructured binding came from', () => {
|
|
63
|
+
const completions = getCompletions({
|
|
64
|
+
source: todo,
|
|
65
|
+
position: todo.length,
|
|
66
|
+
})
|
|
67
|
+
expect(completions.find((c) => c.label === 'h1')?.detail).toBe(
|
|
68
|
+
'∈ elements'
|
|
69
|
+
)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it('filters destructured locals by prefix', () => {
|
|
73
|
+
const src = todo + 'tod'
|
|
74
|
+
const completions = getCompletions({ source: src, position: src.length })
|
|
75
|
+
expect(completions.map((c) => c.label)).toContain('todoApp')
|
|
76
|
+
expect(completions.every((c) => c.label.startsWith('tod'))).toBe(true)
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
|
|
43
80
|
describe('type completions', () => {
|
|
44
81
|
it('should suggest types after colon', () => {
|
|
45
82
|
const completions = getCompletions({
|