tjs-lang 0.6.45 → 0.7.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.
Files changed (95) hide show
  1. package/CLAUDE.md +70 -444
  2. package/README.md +15 -82
  3. package/bin/benchmarks.ts +7 -7
  4. package/bin/dev.ts +2 -1
  5. package/demo/autocomplete.test.ts +1 -1
  6. package/demo/docs.json +743 -47
  7. package/demo/src/demo-nav.ts +5 -5
  8. package/demo/src/index.ts +28 -36
  9. package/demo/src/module-sw.ts +1 -1
  10. package/demo/src/playground-shared.ts +17 -17
  11. package/demo/src/playground.ts +13 -1
  12. package/demo/src/style.ts +4 -1
  13. package/demo/src/tjs-playground.ts +5 -5
  14. package/demo/src/user-store.ts +2 -1
  15. package/demo/static/favicon.svg +17 -24
  16. package/demo/static/tosi-platform.json +9304 -0
  17. package/dist/index.js +176 -175
  18. package/dist/index.js.map +5 -43
  19. package/dist/scripts/compat-effect.d.ts +16 -0
  20. package/dist/scripts/compat-kysely.d.ts +13 -0
  21. package/dist/scripts/compat-radash.d.ts +13 -0
  22. package/dist/scripts/compat-superstruct.d.ts +13 -0
  23. package/dist/scripts/compat-ts-pattern.d.ts +13 -0
  24. package/dist/scripts/compat-zod.d.ts +12 -0
  25. package/dist/src/lang/emitters/from-ts.d.ts +1 -1
  26. package/dist/src/lang/emitters/js-tests.d.ts +4 -0
  27. package/dist/src/lang/emitters/js.d.ts +2 -2
  28. package/dist/src/lang/index.d.ts +1 -0
  29. package/dist/src/lang/json-schema.d.ts +40 -0
  30. package/dist/src/lang/parser-transforms.d.ts +14 -0
  31. package/dist/src/lang/runtime.d.ts +39 -20
  32. package/dist/src/types/Type.d.ts +5 -0
  33. package/dist/tjs-batteries.js +3 -4
  34. package/dist/tjs-batteries.js.map +5 -13
  35. package/dist/tjs-eval.js +47 -0
  36. package/dist/tjs-eval.js.map +7 -0
  37. package/dist/tjs-from-ts.js +58 -0
  38. package/dist/tjs-from-ts.js.map +7 -0
  39. package/dist/tjs-lang.js +349 -0
  40. package/dist/tjs-lang.js.map +7 -0
  41. package/dist/tjs-vm.js +51 -51
  42. package/dist/tjs-vm.js.map +4 -19
  43. package/docs/README.md +21 -20
  44. package/docs/WASM-QUICKSTART.md +283 -0
  45. package/docs/diagrams/architecture-shift.svg +117 -0
  46. package/docs/diagrams/compile-runtime.svg +130 -0
  47. package/docs/diagrams/icon-riff-1.svg +55 -0
  48. package/docs/diagrams/icon-riff-2.svg +62 -0
  49. package/docs/diagrams/icon-riff-3.svg +61 -0
  50. package/docs/diagrams/platform-overview.svg +114 -0
  51. package/docs/diagrams/safe-eval.svg +147 -0
  52. package/docs/eval-v4/arch-comparison.svg +277 -0
  53. package/docs/eval-v4/bundler-tree.svg +250 -0
  54. package/docs/eval-v4/http-lifecycle.svg +148 -0
  55. package/docs/function-predicate-design.md +8 -8
  56. package/docs/native-engine-integration.md +2 -2
  57. package/editors/codemirror/autocomplete.test.ts +29 -29
  58. package/package.json +24 -12
  59. package/src/cli/commands/convert.test.ts +11 -8
  60. package/src/lang/codegen.test.ts +117 -112
  61. package/src/lang/docs.test.ts +22 -22
  62. package/src/lang/docs.ts +5 -8
  63. package/src/lang/emitters/dts.test.ts +13 -13
  64. package/src/lang/emitters/from-ts.ts +36 -9
  65. package/src/lang/emitters/js-tests.ts +143 -28
  66. package/src/lang/emitters/js.ts +44 -31
  67. package/src/lang/features.test.ts +259 -43
  68. package/src/lang/from-ts.test.ts +3 -3
  69. package/src/lang/function-predicate.test.ts +1 -1
  70. package/src/lang/index.ts +8 -47
  71. package/src/lang/json-schema.test.ts +261 -0
  72. package/src/lang/json-schema.ts +167 -0
  73. package/src/lang/parser-params.ts +28 -44
  74. package/src/lang/parser-transforms.ts +255 -0
  75. package/src/lang/parser.test.ts +32 -13
  76. package/src/lang/parser.ts +49 -11
  77. package/src/lang/perf.test.ts +11 -11
  78. package/src/lang/roundtrip.test.ts +3 -3
  79. package/src/lang/runtime.test.ts +167 -0
  80. package/src/lang/runtime.ts +213 -64
  81. package/src/lang/transpiler.test.ts +21 -21
  82. package/src/lang/typescript-syntax.test.ts +11 -9
  83. package/src/types/Type.ts +38 -1
  84. package/src/use-cases/bootstrap.test.ts +7 -7
  85. package/src/use-cases/client-server.test.ts +1 -1
  86. package/src/use-cases/malicious-actor.test.ts +1 -1
  87. package/src/use-cases/rag-processor.test.ts +1 -1
  88. package/src/use-cases/sophisticated-agents.test.ts +2 -2
  89. package/src/use-cases/transpiler-llm.test.ts +1 -1
  90. package/src/use-cases/unbundled-imports.test.ts +9 -9
  91. package/tjs-lang.svg +17 -25
  92. package/dist/tjs-full.js +0 -435
  93. package/dist/tjs-full.js.map +0 -45
  94. package/dist/tjs-transpiler.js +0 -3
  95. package/dist/tjs-transpiler.js.map +0 -11
@@ -18,7 +18,7 @@ describe('TJS Emitter', () => {
18
18
 
19
19
  it('should preserve return type annotation in metadata', () => {
20
20
  const result = transpileToJS(`
21
- function add(a: 0, b: 0) -> 0 {
21
+ function add(a: 0, b: 0): 0 {
22
22
  return a + b
23
23
  }
24
24
  `)
@@ -76,7 +76,7 @@ describe('TJS Emitter', () => {
76
76
 
77
77
  it('should generate __tjs metadata object', () => {
78
78
  const result = transpileToJS(`
79
- function greet(name: 'world') -> 'Hello, world!' {
79
+ function greet(name: 'world'): 'Hello, world!' {
80
80
  return \`Hello, \${name}!\`
81
81
  }
82
82
  `)
@@ -192,7 +192,7 @@ function greet(name: 'world') {
192
192
  it('should handle object return type', () => {
193
193
  // Object types are valid return types
194
194
  const result = transpileToJS(`
195
- function test(x: 0) -> { result: 0 } {
195
+ function test(x: 0): { result: 0 } {
196
196
  return { result: x }
197
197
  }
198
198
  `)
@@ -205,7 +205,7 @@ function greet(name: 'world') {
205
205
  describe('Unsafe functions with (!) syntax', () => {
206
206
  it('should mark function as unsafe when using (!) syntax', () => {
207
207
  const result = transpileToJS(`
208
- function fastAdd(! a: 0, b: 0) -> 0 {
208
+ function fastAdd(! a: 0, b: 0): 0 {
209
209
  return a + b
210
210
  }
211
211
  `)
@@ -214,7 +214,7 @@ function greet(name: 'world') {
214
214
 
215
215
  it('should NOT mark function as unsafe without (!) syntax', () => {
216
216
  const result = transpileToJS(`
217
- function safeAdd(a: 0, b: 0) -> 0 {
217
+ function safeAdd(a: 0, b: 0): 0 {
218
218
  return a + b
219
219
  }
220
220
  `)
@@ -251,7 +251,7 @@ function greet(name: 'world') {
251
251
 
252
252
  it('should preserve type metadata for unsafe functions', () => {
253
253
  const result = transpileToJS(`
254
- function compute(! x: 0, y: 'str') -> 0 {
254
+ function compute(! x: 0, y: 'str'): 0 {
255
255
  return x
256
256
  }
257
257
  `)
@@ -280,8 +280,8 @@ function greet(name: 'world') {
280
280
 
281
281
  it('should handle multiple functions', () => {
282
282
  const result = transpileToJS(`
283
- function add(a: 0, b: 0) -> 0 { return a + b }
284
- function mul(a: 0, b: 0) -> 0 { return a * b }
283
+ function add(a: 0, b: 0): 0 { return a + b }
284
+ function mul(a: 0, b: 0): 0 { return a * b }
285
285
  `)
286
286
 
287
287
  expect(result.code).toContain('add.__tjs')
@@ -293,7 +293,7 @@ function greet(name: 'world') {
293
293
 
294
294
  it('should insert __tjs immediately after each function', () => {
295
295
  const result = transpileToJS(`
296
- function greet(name: 'World') -> 'Hello, World' { return 'Hello, ' + name }
296
+ function greet(name: 'World'): 'Hello, World' { return 'Hello, ' + name }
297
297
  console.log(greet.__tjs)
298
298
  `)
299
299
 
@@ -307,7 +307,7 @@ function greet(name: 'world') {
307
307
 
308
308
  it('should compile validation inline (no wrapper)', () => {
309
309
  const result = transpileToJS(`
310
- function greet(name: 'World') -> 'Hello, World' { return 'Hello, ' + name }
310
+ function greet(name: 'World'): 'Hello, World' { return 'Hello, ' + name }
311
311
  `)
312
312
 
313
313
  // Should NOT have wrapper pattern
@@ -324,11 +324,11 @@ function greet(name: 'world') {
324
324
  const result = transpileToJS(`
325
325
  const VERSION = '1.0'
326
326
 
327
- function greet(name: 'World') -> 'Hello, World' { return 'Hello, ' + name }
327
+ function greet(name: 'World'): 'Hello, World' { return 'Hello, ' + name }
328
328
 
329
329
  console.log(greet.__tjs)
330
330
 
331
- function add(a: 1, b: 2) -> 3 { return a + b }
331
+ function add(a: 1, b: 2): 3 { return a + b }
332
332
 
333
333
  console.log(add.__tjs)
334
334
  `)
@@ -373,7 +373,7 @@ function greet(name: 'world') {
373
373
  it('should handle export function with __tjs metadata', () => {
374
374
  const result = transpileToJS(
375
375
  `
376
- export function add(a: 1.0, b: 2.0) -> 3.0 {
376
+ export function add(a: 1.0, b: 2.0): 3.0 {
377
377
  return a + b
378
378
  }
379
379
  `,
@@ -389,7 +389,7 @@ function greet(name: 'world') {
389
389
  it('should handle export default function with __tjs metadata', () => {
390
390
  const result = transpileToJS(
391
391
  `
392
- export default function greet(name: 'World') -> '' {
392
+ export default function greet(name: 'World'): '' {
393
393
  return 'Hello, ' + name
394
394
  }
395
395
  `,
@@ -405,11 +405,11 @@ function greet(name: 'world') {
405
405
  `
406
406
  import { helper } from './utils.tjs'
407
407
 
408
- function internal(x: 0) -> 0 {
408
+ function internal(x: 0): 0 {
409
409
  return x * 2
410
410
  }
411
411
 
412
- export function api(y: 0) -> 0 {
412
+ export function api(y: 0): 0 {
413
413
  return internal(helper(y))
414
414
  }
415
415
  `,
@@ -444,7 +444,7 @@ function greet(name: 'world') {
444
444
  it('should generate inline validation for exported functions', () => {
445
445
  const result = transpileToJS(
446
446
  `
447
- export function add(a: 0, b: 0) -> 0 {
447
+ export function add(a: 0, b: 0): 0 {
448
448
  return a + b
449
449
  }
450
450
  `,
@@ -462,13 +462,13 @@ function greet(name: 'world') {
462
462
  # Example
463
463
 
464
464
  \`\`\`javascript
465
- export function add(a: 0, b: 0) -> 0 {
465
+ export function add(a: 0, b: 0): 0 {
466
466
  return a + b
467
467
  }
468
468
  \`\`\`
469
469
  */
470
470
 
471
- function realFunction(x: 5) -> 10 {
471
+ function realFunction(x: 5): 10 {
472
472
  return x * 2
473
473
  }
474
474
  `,
@@ -493,7 +493,7 @@ add.__tjs = { params: { a: { type: { kind: 'number' } }, b: { type: { kind: 'num
493
493
  const mainSource = `
494
494
  import { add } from 'mymath'
495
495
 
496
- function doubleAdd(x: 5) -> 20 {
496
+ function doubleAdd(x: 5): 20 {
497
497
  return add(x, x) * 2
498
498
  }
499
499
  `
@@ -521,7 +521,7 @@ multiply.__tjs = { params: { a: { type: { kind: 'number' } }, b: { type: { kind:
521
521
  const mainSource = `
522
522
  import { multiply } from 'mymath'
523
523
 
524
- function square(x: 0) -> 0 {
524
+ function square(x: 0): 0 {
525
525
  return multiply(x, x)
526
526
  }
527
527
 
@@ -155,7 +155,7 @@ describe('Union Types', () => {
155
155
 
156
156
  test('union return type with | (nullable object)', () => {
157
157
  const { metadata } = transpileToJS(`
158
- function find(id: 0) -! { name: '' } | null {
158
+ function find(id: 0):! { name: '' } | null {
159
159
  return null
160
160
  }
161
161
  `)
@@ -228,7 +228,7 @@ describe('Return Types', () => {
228
228
  test('simple return type', () => {
229
229
  // Use -! to skip signature test (testing metadata, not return value match)
230
230
  const { metadata } = transpileToJS(`
231
- function greet(name: '') -! '' {
231
+ function greet(name: ''):! '' {
232
232
  return 'Hello, ' + name
233
233
  }
234
234
  `)
@@ -238,7 +238,7 @@ describe('Return Types', () => {
238
238
  test('object return type', () => {
239
239
  // Use -! to skip signature test (testing metadata, not return value match)
240
240
  const { metadata } = transpileToJS(`
241
- function makeUser(name: '') -! { name: '', id: 0 } {
241
+ function makeUser(name: ''):! { name: '', id: 0 } {
242
242
  return { name, id: 1 }
243
243
  }
244
244
  `)
@@ -248,7 +248,7 @@ describe('Return Types', () => {
248
248
 
249
249
  test('array return type', () => {
250
250
  const { metadata } = transpileToJS(`
251
- function toArray(item: '') -> [''] {
251
+ function toArray(item: ''): [''] {
252
252
  return [item]
253
253
  }
254
254
  `)
@@ -258,7 +258,7 @@ describe('Return Types', () => {
258
258
 
259
259
  test('nested array return ([[x]])', () => {
260
260
  const { metadata } = transpileToJS(`
261
- function chunk(items: [''], size: 1) -> [['']] {
261
+ function chunk(items: [''], size: 1): [['']] {
262
262
  const result = []
263
263
  for (let i = 0; i < items.length; i += size) {
264
264
  result.push(items.slice(i, i + size))
@@ -628,6 +628,7 @@ describe('Class Syntax', () => {
628
628
  const { transpile } = require('./index')
629
629
  expect(() =>
630
630
  transpile(`
631
+ TjsCompat
631
632
  class Greeter {
632
633
  greet() {
633
634
  return 'Hello'
@@ -854,7 +855,8 @@ describe('Real-World Patterns', () => {
854
855
  }).code
855
856
  // TJS should have union annotation
856
857
  expect(tjsCode).toContain('excited: false | undefined')
857
- const jsResult = tjs(tjsCode)
858
+ // TS-originated code defaults to safety none — add safety inputs to test validation
859
+ const jsResult = tjs('safety inputs\n' + tjsCode)
858
860
  // JS should not have default or bitwise OR — `:` means required
859
861
  expect(jsResult.code).not.toMatch(/excited = false/)
860
862
  expect(jsResult.code).not.toMatch(/excited = false \| undefined/)
@@ -898,7 +900,7 @@ describe('fromTS generators', () => {
898
900
  emitTJS: true,
899
901
  })
900
902
  // Return annotation should be the yield type (number -> 0.0)
901
- expect(result.code).toContain('-!')
903
+ expect(result.code).toContain(':!')
902
904
  expect(result.code).toContain('0.0')
903
905
  })
904
906
 
@@ -907,7 +909,7 @@ describe('fromTS generators', () => {
907
909
  "async function* words(): AsyncGenerator<string> { yield 'hi' }",
908
910
  { emitTJS: true }
909
911
  )
910
- expect(result.code).toContain('-!')
912
+ expect(result.code).toContain(':!')
911
913
  expect(result.code).toMatch(/''/)
912
914
  })
913
915
 
@@ -1645,7 +1647,7 @@ describe('DOM Types', () => {
1645
1647
  { emitTJS: true }
1646
1648
  )
1647
1649
  // Return type should be {} not degraded
1648
- expect(result.code).toContain('-! {}')
1650
+ expect(result.code).toContain(':! {}')
1649
1651
  })
1650
1652
 
1651
1653
  test('DOM callback type preserves annotation', () => {
package/src/types/Type.ts CHANGED
@@ -16,7 +16,8 @@
16
16
  * ZipCode.description // '5-digit US zip code'
17
17
  */
18
18
 
19
- import { validate, s, type Base } from 'tosijs-schema'
19
+ import { validate, filter as schemaFilter, s, type Base } from 'tosijs-schema'
20
+ import { exampleToJSONSchema, type JSONSchemaObject } from '../lang/json-schema'
20
21
 
21
22
  /** JSON Schema object type (simplified) */
22
23
  type JSONSchema = {
@@ -46,6 +47,10 @@ export interface RuntimeType<T = unknown> {
46
47
  readonly examples?: T[]
47
48
  /** Default value (for instantiation) */
48
49
  readonly default?: T
50
+ /** Generate JSON Schema for this type */
51
+ toJSONSchema(): JSONSchemaObject
52
+ /** Strip a value down to only the fields matching this type's schema */
53
+ strip(value: unknown): unknown
49
54
  /** Brand for type identification */
50
55
  readonly __runtimeType: true
51
56
  }
@@ -189,6 +194,28 @@ export function Type<T = unknown>(
189
194
  example,
190
195
  examples,
191
196
  default: defaultValue,
197
+ toJSONSchema(): JSONSchemaObject {
198
+ // If we have an underlying JSON Schema or builder, extract it
199
+ if (schema) {
200
+ const raw = (schema as any)?.schema ?? schema
201
+ if (raw && typeof raw === 'object' && 'type' in raw) {
202
+ return raw as JSONSchemaObject
203
+ }
204
+ }
205
+ // Fall back to inferring from example
206
+ if (example !== undefined) {
207
+ return exampleToJSONSchema(example)
208
+ }
209
+ // Predicate-only types: best-effort from description
210
+ return { description }
211
+ },
212
+ strip(value: unknown): unknown {
213
+ if (schema) {
214
+ return schemaFilter(value, schema)
215
+ }
216
+ // No schema — can't strip, return as-is
217
+ return value
218
+ },
192
219
  __runtimeType: true as const,
193
220
  }
194
221
  }
@@ -386,6 +413,10 @@ export function Union<T extends unknown[]>(
386
413
  const result: RuntimeType & { values: unknown[] } = {
387
414
  description,
388
415
  check: (v: unknown): v is T[number] => valueSet.has(v),
416
+ toJSONSchema: () => ({
417
+ enum: values,
418
+ }),
419
+ strip: (value: unknown) => value,
389
420
  __runtimeType: true as const,
390
421
  values, // Expose values for introspection
391
422
  }
@@ -599,6 +630,10 @@ export function Enum<T extends Record<string, string | number>>(
599
630
  const enumType: EnumType<T> = {
600
631
  description,
601
632
  check: (v: unknown): v is T[keyof T] => valueSet.has(v as T[keyof T]),
633
+ toJSONSchema: () => ({
634
+ enum: values as unknown[],
635
+ }),
636
+ strip: (value: unknown) => value,
602
637
  __runtimeType: true as const,
603
638
  members,
604
639
  names,
@@ -783,6 +818,8 @@ function _createFunctionPredicate(
783
818
  params,
784
819
  returns,
785
820
  returnContract,
821
+ toJSONSchema: () => ({ description: name, type: 'function' as any }),
822
+ strip: (value: unknown) => value,
786
823
  // eslint-disable-next-line @typescript-eslint/ban-types
787
824
  check: (value: unknown): value is Function => {
788
825
  if (typeof value !== 'function') return false
@@ -151,11 +151,11 @@ describe('Bootstrap Canary', () => {
151
151
  Basic arithmetic operations.
152
152
  */
153
153
 
154
- function add(a: 0, b: 0) -> 0 {
154
+ function add(a: 0, b: 0): 0 {
155
155
  return a + b
156
156
  }
157
157
 
158
- function multiply(x: 1, y: 1) -> 1 {
158
+ function multiply(x: 1, y: 1): 1 {
159
159
  return x * y
160
160
  }
161
161
  `)
@@ -182,14 +182,14 @@ describe('Bootstrap Canary', () => {
182
182
 
183
183
  // A self-contained TJS test
184
184
  const tjsSource = `
185
- function add(a: 0, b: 0) -> 0 {
185
+ function add(a: 0, b: 0): 0 {
186
186
  return a + b
187
187
  }
188
188
  /* @test add(1, 2) is 3 */
189
189
  /* @test add(-1, 1) is 0 */
190
190
  /* @test add(0, 0) is 0 */
191
191
 
192
- function greet(name: 'World') -> 'Hello, World!' {
192
+ function greet(name: 'World'): 'Hello, World!' {
193
193
  return 'Hello, ' + name + '!'
194
194
  }
195
195
  /* @test greet('TJS') is 'Hello, TJS!' */
@@ -541,7 +541,7 @@ describe('Bootstrap Canary', () => {
541
541
 
542
542
  // Test colon shorthand -> default params
543
543
  const result1 = parserModule.preprocess(`
544
- function greet(name: 'World') -> '' {
544
+ function greet(name: 'World'): '' {
545
545
  return 'Hello, ' + name + '!'
546
546
  }
547
547
  `)
@@ -550,7 +550,7 @@ describe('Bootstrap Canary', () => {
550
550
 
551
551
  // Test arrow return type extraction
552
552
  const result2 = parserModule.preprocess(`
553
- function add(a: 0, b: 0) -> 0 {
553
+ function add(a: 0, b: 0): 0 {
554
554
  return a + b
555
555
  }
556
556
  `)
@@ -650,7 +650,7 @@ describe('Bootstrap Canary', () => {
650
650
  // Test cases - various TJS syntax
651
651
  const testCases = [
652
652
  `function f(x: 0) { return x }`,
653
- `function g(a: '', b = 1) -> '' { return a }`,
653
+ `function g(a: '', b = 1): '' { return a }`,
654
654
  `function h(! fast: 0) { return fast }`,
655
655
  `Type Foo { example: { x: 0 } }`,
656
656
  `Generic Bar<T> { predicate(x, T) { return true } }`,
@@ -78,7 +78,7 @@ describe('Use Case: Client-Server', () => {
78
78
  }
79
79
 
80
80
  // 3. Verify
81
- // store.get('secret_id') -> 'Server Value for secret_id'
81
+ // store.get('secret_id'): 'Server Value for secret_id'
82
82
  // template -> 'Echo: Server Value for secret_id'
83
83
  expect(response.status).toBe(200)
84
84
  expect(data.result).toEqual({
@@ -20,7 +20,7 @@ describe('Use Case: Malicious Actor', () => {
20
20
  expect(result.error).toBeDefined()
21
21
  expect(result.error?.message).toBe('Out of Fuel')
22
22
 
23
- // 2. Run with enough fuel (simulated) -> Should fail eventually or return if limited loops
23
+ // 2. Run with enough fuel (simulated): Should fail eventually or return if limited loops
24
24
  // In this case condition is always true, so it loops forever.
25
25
  // Even with 1000000 fuel, it will exhaust it.
26
26
  })
@@ -101,7 +101,7 @@ describe('Use Case: RAG Processor', () => {
101
101
  // We need robust resolve?
102
102
  // Since we can't import resolveValue, we rely on ctx.capabilities.llm.embed
103
103
  // But wait, 'text' in step might be 'args.query' string if resolved by builder?
104
- // Builder: Agent.args('query') -> { $kind: 'arg', path: 'query' }
104
+ // Builder: Agent.args('query'): { $kind: 'arg', path: 'query' }
105
105
  // So step.text is that object.
106
106
  // We need resolveValue logic.
107
107
  // But I can't import resolveValue.
@@ -86,8 +86,8 @@ describe('Use Case: Sophisticated Agents', () => {
86
86
  )
87
87
 
88
88
  expect(result.result.answer).toBe('A')
89
- // Attempt 0: "Paris" (Invalid) -> attempts becomes 1
90
- // Attempt 1: "A" (Valid) -> success
89
+ // Attempt 0: "Paris" (Invalid): attempts becomes 1
90
+ // Attempt 1: "A" (Valid): success
91
91
  // So attempts variable ends at 1.
92
92
  expect(result.result.attempts).toBe(1)
93
93
  expect(caps.llmBattery.predict).toHaveBeenCalledTimes(2)
@@ -78,7 +78,7 @@ function fixCommonMistakes(code: string): string {
78
78
  )
79
79
 
80
80
  // Fix TypeScript-style type annotations on parameters
81
- // e.g., (x: string) -> (x: 'example') or (x: number) -> (x: 0)
81
+ // e.g., (x: string): (x: 'example') or (x: number): (x: 0)
82
82
  // Only do this for standalone type keywords, not example values
83
83
  code = code.replace(/:\s*string\b(?!\s*[=)])/g, ": ''")
84
84
  code = code.replace(/:\s*number\b(?!\s*[=)])/g, ': 0')
@@ -33,7 +33,7 @@ describe('Unbundled transitive imports', () => {
33
33
  it('should share runtime across files importing each other', async () => {
34
34
  // File A: exports a validated function
35
35
  const aSource = `
36
- export function double(x: 0) -! 0 {
36
+ export function double(x: 0):! 0 {
37
37
  return x * 2
38
38
  }
39
39
  `
@@ -43,7 +43,7 @@ describe('Unbundled transitive imports', () => {
43
43
  const bSource = `
44
44
  import { double } from './a.js'
45
45
 
46
- export function quadruple(x: 0) -! 0 {
46
+ export function quadruple(x: 0):! 0 {
47
47
  return double(double(x))
48
48
  }
49
49
  `
@@ -63,7 +63,7 @@ describe('Unbundled transitive imports', () => {
63
63
  it('should propagate MonadicError across file boundaries', async () => {
64
64
  // File C: validates input
65
65
  const cSource = `
66
- export function validateName(name: '') -! '' {
66
+ export function validateName(name: ''):! '' {
67
67
  return name.trim()
68
68
  }
69
69
  `
@@ -73,7 +73,7 @@ describe('Unbundled transitive imports', () => {
73
73
  const dSource = `
74
74
  import { validateName } from './c.js'
75
75
 
76
- export function greetUser(name: '') -! '' {
76
+ export function greetUser(name: ''):! '' {
77
77
  const clean = validateName(name)
78
78
  if (clean instanceof Error) return clean
79
79
  return 'Hello, ' + clean + '!'
@@ -131,11 +131,11 @@ describe('Unbundled transitive imports', () => {
131
131
  it('should not create duplicate MonadicError classes at runtime', async () => {
132
132
  // Both files have inline MonadicError but should use shared runtime
133
133
  const e1Source = `
134
- export function check1(x: '') -! '' { return x }
134
+ export function check1(x: ''):! '' { return x }
135
135
  `
136
136
  const e2Source = `
137
137
  import { check1 } from './e1.js'
138
- export function check2(x: '') -! '' { return check1(x) }
138
+ export function check2(x: ''):! '' { return check1(x) }
139
139
  `
140
140
 
141
141
  writeFileSync(join(TEMP_DIR, 'e1.js'), tjs(e1Source).code)
@@ -150,14 +150,14 @@ describe('Unbundled transitive imports', () => {
150
150
  })
151
151
 
152
152
  it('should handle three-level import chains', async () => {
153
- const l1 = `export function inc(x: 0) -! 0 { return x + 1 }`
153
+ const l1 = `export function inc(x: 0):! 0 { return x + 1 }`
154
154
  const l2 = `
155
155
  import { inc } from './l1.js'
156
- export function incTwice(x: 0) -! 0 { return inc(inc(x)) }
156
+ export function incTwice(x: 0):! 0 { return inc(inc(x)) }
157
157
  `
158
158
  const l3 = `
159
159
  import { incTwice } from './l2.js'
160
- export function incFour(x: 0) -! 0 { return incTwice(incTwice(x)) }
160
+ export function incFour(x: 0):! 0 { return incTwice(incTwice(x)) }
161
161
  `
162
162
 
163
163
  writeFileSync(join(TEMP_DIR, 'l1.js'), tjs(l1).code)
package/tjs-lang.svg CHANGED
@@ -1,31 +1,23 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
- <svg x="0pt" y="0pt" width="48pt" height="48pt" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
2
+ <svg x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
3
3
  <!--Generated by AMDN-->
4
- <g id="Layer_1">
5
- <g id="Layer_1-1">
6
- <g id="Layer_1_1">
7
- <g id="Group">
8
- <path id="Path" style="fill:#ff1c24;fill-opacity:1;fill-rule:evenodd;opacity:1;stroke:none;" d="M1,9 C1,4.58172,4.58172,1,9,1 C9,1,39,1,39,1 C43.4183,1,47,4.58172,47,9 C47,9,47,39,47,39 C47,43.4183,43.4183,47,39,47 C39,47,9,47,9,47 C4.58172,47,1,43.4183,1,39 C1,39,1,9,1,9 z"/>
9
- <g id="Group_1">
10
- <path id="Path_1" style="fill:#9e9e9e;fill-opacity:1;fill-rule:nonzero;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M16,29 C16,29,10,31,10,35 C10,39,16,39,16,39"/>
11
- <path id="Path_Copy" style="fill:#9e9e9e;fill-opacity:1;fill-rule:nonzero;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M32.0002,29 C32.0002,29,38.0002,31,38.0002,35 C38.0002,39,32.0002,39,32.0002,39"/>
12
- <path id="Path_2" style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M9,10.1818 C9,7.87226,10.7909,6,13,6 C13,6,35,6,35,6 C37.2091,6,39,7.87226,39,10.1818 C39,10.1818,39,24.8182,39,24.8182 C39,27.1277,37.2091,29,35,29 C35,29,13,29,13,29 C10.7909,29,9,27.1277,9,24.8182 C9,24.8182,9,10.1818,9,10.1818 z"/>
13
- <path id="Path_3" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M24,11 C24,11,24,23,24,23"/>
14
- <path id="Path_4" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M28,15 C28,15,28,17,28,17"/>
15
- <path id="Path_Copy_1" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M20,15 C20,15,20,17,20,17"/>
16
- <path id="Path_5" style="fill:none;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M32,43 C32,43,30,41,30,41 C30,41,28,43,28,43"/>
17
- <path id="Path_Copy_2" style="fill:none;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M20,43 C20,43,18,41,18,41 C18,41,16,43,16,43"/>
18
- <path id="Path_6" style="fill:#e4e4e4;fill-opacity:1;fill-rule:evenodd;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M16,29 C16,29,32,29,32,29 C32,29,32,39,32,39 C32,39,16,39,16,39 C16,39,16,29,16,29 z"/>
19
- </g>
20
- </g>
4
+ <g id="Layer 1">
5
+ <g id="Group">
6
+ <g id="Group">
7
+ <path id="Path 17" style="fill:#3ea9f5;fill-opacity:1;fill-rule:evenodd;opacity:1;stroke:none;" d="M23.9725,47 C23.9725,47,39,47,39,47 C43.4183,47,47,43.4183,47,39 C47,39,47,9,47,9 C47,4.58172,43.4183,1,39,1 C39,1,9,1,9,1 C4.58172,1,1,4.58172,1,9 C1,9,1,39,1,39 C1,41.6412,2.27995,43.9835,4.25342,45.4404 C4.08812,44.8215,4,44.171,4,43.5 C4,39.3579,7.35786,36,11.5,36 C15.1444,36,18.1817,38.5994,18.859,42.0453 C19.0684,42.0154,19.2824,42,19.5,42 C21.9853,42,24,44.0147,24,46.5 C24,46.669,23.9907,46.8358,23.9725,47 z"/>
8
+ <path id="Path 18" style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;opacity:1;stroke:none;" d="M4.25342,45.4404 C4.08812,44.8215,4,44.171,4,43.5 C4,39.3579,7.35786,36,11.5,36 C15.1444,36,18.1817,38.5994,18.859,42.0453 C19.0684,42.0154,19.2824,42,19.5,42 C21.9853,42,24,44.0147,24,46.5 C24,46.669,23.9907,46.8358,23.9725,47 C23.9725,47,9,47,9,47 C7.22294,47,5.58121,46.4206,4.25342,45.4404 z"/>
9
+ </g>
10
+ <path id="Path" style="fill:none;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M35,35 C35,35,32.1716,35,32.1716,35 C32.1716,35,32.1716,37.8284,32.1716,37.8284"/>
11
+ <path id="Path Copy" style="fill:none;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M31,39 C31,39,28.1716,39,28.1716,39 C28.1716,39,28.1716,41.8284,28.1716,41.8284"/>
12
+ <path id="Path Copy" style="fill:#9e9e9e;fill-opacity:1;fill-rule:nonzero;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M7.48047,16 C4.45369,16,2,18.4537,2,21.4805 C2,21.4805,2,21.4805,2,21.4805 C2,23.9765,4.02346,26,6.51953,26 C6.51953,26,6.61997,26,6.61997,26 C7.38213,26,8,26.6179,8,27.38 C8,27.38,8,27.38,8,27.38 C8,29.9316,10.0684,32,12.62,32 C12.62,32,16,32,16,32 C18.5834,32,20.6777,29.9057,20.6777,27.3223 C20.6777,27.3223,20.6777,21.4215,20.6777,21.4215 C20.6777,18.4273,18.2504,16,15.2561,16 C15.2561,16,7.48047,16,7.48047,16 z"/>
13
+ <path id="Path" style="fill:#e4e4e4;fill-opacity:1;fill-rule:evenodd;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M17,29 C17,29,33,29,33,29 C33,29,33,29,33,29 C33,34.5228,28.5228,39,23,39 C23,39,23,39,23,39 C19.6863,39,17,36.3137,17,33 C17,33,17,29,17,29 z"/>
14
+ <path id="Path Copy" style="fill:#9e9e9e;fill-opacity:1;fill-rule:nonzero;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M40.5195,16 C43.5463,16,46,18.4537,46,21.4805 C46,21.4805,46,21.4805,46,21.4805 C46,23.9765,43.9765,26,41.4805,26 C41.4805,26,41.38,26,41.38,26 C40.6179,26,40,26.6179,40,27.38 C40,27.38,40,27.38,40,27.38 C40,29.9316,37.9316,32,35.38,32 C35.38,32,32,32,32,32 C29.4166,32,27.3223,29.9057,27.3223,27.3223 C27.3223,27.3223,27.3223,21.4215,27.3223,21.4215 C27.3223,18.4273,29.7496,16,32.7439,16 C32.7439,16,40.5195,16,40.5195,16 z"/>
15
+ <g id="Group">
16
+ <path id="Path" style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M6,10.1818 C6,7.87226,7.79086,6,10,6 C10,6,32,6,32,6 C34.2091,6,36,7.87226,36,10.1818 C36,10.1818,36,24.8182,36,24.8182 C36,27.1277,34.2091,29,32,29 C32,29,10,29,10,29 C7.79086,29,6,27.1277,6,24.8182 C6,24.8182,6,10.1818,6,10.1818 z"/>
17
+ <path id="Path" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M21,11 C21,11,21,23,21,23"/>
18
+ <path id="Path" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M25,15 C25,15,25,17,25,17"/>
19
+ <path id="Path Copy" style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M17,15 C17,15,17,17,17,17"/>
21
20
  </g>
22
21
  </g>
23
- <path id="Path-1" style="fill:#006736;fill-opacity:1;fill-rule:evenodd;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M27,17 C27,17,34,17,34,17 C34,17,34,22,34,22 C34,22,27,22,27,22 C27,22,27,17,27,17 z"/>
24
- <path id="Path-2" style="fill:none;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M21,19 C21,19,21,19,21,19 C21,17.8954,21.8954,17,23,17 C23,17,25,17,25,17 C26.1046,17,27,17.8954,27,19 C27,19,27,19,27,19"/>
25
- <path id="Path_Copy-1" style="fill:#006736;fill-opacity:1;fill-rule:evenodd;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M14,17 C14,17,21,17,21,17 C21,17,21,22,21,22 C21,22,14,22,14,22 C14,22,14,17,14,17 z"/>
26
- <path id="Path_Copy-2" style="fill:#8e7f6d;fill-opacity:1;fill-rule:nonzero;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M7.31734,20.5867 C7.14208,19.7104,7.71038,18.8579,8.58668,18.6827 C8.58668,18.6827,10.4133,18.3173,10.4133,18.3173 C11.2896,18.1421,12.1421,18.7104,12.3173,19.5867 C12.3173,19.5867,12.6405,21.2026,12.6405,21.2026 C12.8314,22.157,13.8156,22.7281,14.7389,22.4204 C14.7389,22.4204,15.1785,22.2738,15.1785,22.2738 C15.6917,22.1028,16.2565,22.1995,16.6836,22.5317 C16.6836,22.5317,24.3753,28.5141,24.3753,28.5141 C24.7695,28.8207,25,29.2921,25,29.7914 C25,29.7914,25,40.3298,25,40.3298 C25,40.7589,24.8295,41.1705,24.5261,41.4739 C24.5261,41.4739,23.4739,42.5261,23.4739,42.5261 C23.1705,42.8295,22.7589,43,22.3298,43 C22.3298,43,9,43,9,43 C7.34315,43,6,41.6569,6,40 C6,40,6,26,6,26 C6,25.3871,6.3463,24.8268,6.89452,24.5527 C6.89452,24.5527,6.89452,24.5527,6.89452,24.5527 C7.5472,24.2264,7.90073,23.5036,7.75762,22.7881 C7.75762,22.7881,7.31734,20.5867,7.31734,20.5867 z"/>
27
- <path id="Compound_Group" style="fill:#c6b199;fill-opacity:1;fill-rule:evenodd;opacity:1;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M21.118,26.0132 C21.118,26.0132,29.4076,27.8928,29.4076,27.8928 C30.2155,28.076,30.722,28.8794,30.5388,29.6874 C30.5388,29.6874,28.3275,39.4398,28.3275,39.4398 C28.1443,40.2477,27.3409,40.7542,26.5329,40.571 C26.5329,40.571,10.929,37.0329,10.929,37.0329 C10.1211,36.8498,9.61466,36.0463,9.79785,35.2384 C9.79785,35.2384,12.2302,24.5107,12.2302,24.5107 C12.2302,24.5107,12.6725,22.5602,12.6725,22.5602 C12.8557,21.7523,13.6591,21.2458,14.4671,21.429 C14.4671,21.429,20.3185,22.7558,20.3185,22.7558 C21.1264,22.939,21.6329,23.7424,21.4497,24.5503 C21.4497,24.5503,21.118,26.0132,21.118,26.0132 z"/>
28
- <path id="Path-3" style="fill:#8e7f6d;fill-opacity:1;fill-rule:nonzero;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M41,19 C41,19,36,18,36,18 C36,18,35,23,35,23 C35,23,32,22,32,22 C32,22,23,29,23,29 C23,29,23,41,23,41 C23,41,25,43,25,43 C25,43,39,43,39,43 C40.6569,43,42,41.6569,42,40 C42,40,42,25,42,25 C42,25,40,24,40,24 C40,24,41,19,41,19 z"/>
29
- <path id="Path-4" style="fill:#8e7f6d;fill-opacity:1;fill-rule:nonzero;opacity:1;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1;stroke-width:2;" d="M13.2766,3.05029 C13.1062,3.01931,12.9326,3.08429,12.8244,3.21952 C12.8244,3.21952,9,8,9,8 C9,8,6.05462,8.58908,6.05462,8.58908 C5.56174,8.68765,5.54512,9.38628,6.03275,9.50819 C6.03275,9.50819,24,14,24,14 C24,14,41.9672,9.50819,41.9672,9.50819 C42.4549,9.38628,42.4383,8.68765,41.9454,8.58908 C41.9454,8.58908,39,8,39,8 C39,8,35.1756,3.21952,35.1756,3.21952 C35.0674,3.08429,34.8938,3.01931,34.7234,3.05029 C34.7234,3.05029,24,5,24,5 C24,5,13.2766,3.05029,13.2766,3.05029 z"/>
30
22
  </g>
31
23
  </svg>