tjs-lang 0.8.2 → 0.8.4
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 +5 -2
- package/demo/autocomplete.test.ts +37 -0
- package/demo/docs.json +701 -11
- 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 +53 -0
- package/demo/src/tjs-playground.ts +21 -0
- package/dist/experiments/predicates/css.predicates.d.ts +13 -0
- package/dist/experiments/predicates/verify.d.ts +39 -0
- package/dist/index.js +101 -97
- package/dist/index.js.map +4 -4
- package/dist/src/lang/index.d.ts +2 -0
- package/dist/src/lang/predicate-schema.d.ts +39 -0
- package/dist/src/lang/predicate.d.ts +103 -0
- package/dist/src/lang/transpiler.d.ts +2 -0
- package/dist/src/vm/runtime.d.ts +22 -0
- package/dist/tjs-eval.js +29 -29
- 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 +86 -82
- package/dist/tjs-lang.js.map +4 -4
- package/dist/tjs-vm.js +45 -45
- 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/package.json +2 -1
- package/src/lang/index.ts +22 -0
- 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/runtime.test.ts +46 -0
- package/src/lang/suggest.test.ts +84 -0
- package/src/lang/transpiler.ts +26 -0
- package/src/runtime.test.ts +6 -6
- package/src/vm/atom-effects.test.ts +72 -0
- package/src/vm/atoms/batteries.ts +12 -0
- package/src/vm/equality.test.ts +59 -0
- package/src/vm/runtime.ts +77 -59
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)
|
|
@@ -264,7 +266,7 @@ Coverage targets: 98% lines on `src/vm/runtime.ts` (security-critical), 80%+ ove
|
|
|
264
266
|
|
|
265
267
|
### Adding a New Atom
|
|
266
268
|
|
|
267
|
-
1. Define with `defineAtom(opCode, inputSchema, outputSchema, implementation, { cost, timeoutMs, docs })`
|
|
269
|
+
1. Define with `defineAtom(opCode, inputSchema, outputSchema, implementation, { cost, timeoutMs, docs, effects })`
|
|
268
270
|
2. Add to `src/vm/atoms/` and export from `src/vm/atoms/index.ts`
|
|
269
271
|
3. Add tests
|
|
270
272
|
4. Run `bun run test:fast`
|
|
@@ -274,6 +276,7 @@ Coverage targets: 98% lines on `src/vm/runtime.ts` (security-critical), 80%+ ove
|
|
|
274
276
|
- `cost` can be static number or dynamic: `(input, ctx) => number`
|
|
275
277
|
- `timeoutMs` defaults to 1000ms; use `0` for no timeout (e.g., `seq`)
|
|
276
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`.
|
|
277
280
|
|
|
278
281
|
### Debugging Agents
|
|
279
282
|
|
|
@@ -311,7 +314,7 @@ Full syntax documentation is in [`CLAUDE-TJS-SYNTAX.md`](CLAUDE-TJS-SYNTAX.md).
|
|
|
311
314
|
- **Bang access**: `x!.foo` — returns MonadicError if `x` is null/undefined, otherwise bare `x.foo`. Chains propagate: `x!.foo!.bar`.
|
|
312
315
|
- **Type/Generic/FunctionPredicate**: Three declaration forms for runtime type predicates
|
|
313
316
|
- **`const!`**: Compile-time immutability, zero runtime cost
|
|
314
|
-
- **Equality**: `==`/`!=`
|
|
317
|
+
- **Equality**: `==`/`!=` in native TJS (via `Eq`/`NotEq` under `TjsEquals`) are **footgun-free `===`** — they unwrap boxed primitives (`new Boolean(false) == false`) and treat `null`/`undefined` as equal, but do **NOT** coerce types (`'5' != 5`, `'' != false`) and are **NOT structural** (distinct objects/arrays are distinct: `{a:1} != {a:1}` — a real distinction, and structural `==` would be a silent O(n) hit). For deep structural comparison use the `Is`/`IsNot` function (or a type's `.Equals` hook). `===`/`!==` = strict identity.
|
|
315
318
|
- **Polymorphic functions**: Multiple same-name declarations merge into arity/type dispatcher
|
|
316
319
|
- **`extend` blocks**: Local class extensions without prototype pollution
|
|
317
320
|
- **WASM blocks**: Inline WebAssembly compiled at transpile time, with SIMD intrinsics and `wasmBuffer()` zero-copy arrays
|
|
@@ -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({
|