tjs-lang 0.8.1 → 0.8.2

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 (61) hide show
  1. package/CLAUDE.md +9 -3
  2. package/demo/examples.test.ts +6 -2
  3. package/demo/src/playground-shared.ts +48 -16
  4. package/demo/src/playground-test-results.test.ts +112 -0
  5. package/demo/src/tjs-playground.ts +11 -5
  6. package/dist/examples/modules/dist/main.d.ts +34 -0
  7. package/dist/examples/modules/dist/math.d.ts +120 -0
  8. package/dist/index.js +115 -112
  9. package/dist/index.js.map +4 -4
  10. package/dist/src/lang/core.d.ts +1 -1
  11. package/dist/src/lang/dialect.d.ts +35 -0
  12. package/dist/src/lang/emitters/ast.d.ts +1 -1
  13. package/dist/src/lang/emitters/js-tests.d.ts +7 -0
  14. package/dist/src/lang/emitters/js.d.ts +12 -0
  15. package/dist/src/lang/index.d.ts +2 -1
  16. package/dist/src/lang/parser-types.d.ts +17 -0
  17. package/dist/src/lang/parser.d.ts +18 -0
  18. package/dist/src/lang/transpiler.d.ts +1 -0
  19. package/dist/src/lang/types.d.ts +18 -0
  20. package/dist/src/vm/runtime.d.ts +18 -0
  21. package/dist/src/vm/vm.d.ts +15 -1
  22. package/dist/tjs-batteries.js +2 -2
  23. package/dist/tjs-batteries.js.map +2 -2
  24. package/dist/tjs-eval.js +43 -43
  25. package/dist/tjs-eval.js.map +3 -3
  26. package/dist/tjs-from-ts.js +1 -1
  27. package/dist/tjs-from-ts.js.map +2 -2
  28. package/dist/tjs-lang.js +76 -73
  29. package/dist/tjs-lang.js.map +4 -4
  30. package/dist/tjs-vm.js +49 -49
  31. package/dist/tjs-vm.js.map +3 -3
  32. package/llms.txt +1 -0
  33. package/package.json +20 -1
  34. package/src/batteries/audit.ts +3 -2
  35. package/src/cli/commands/check.ts +3 -2
  36. package/src/cli/commands/emit.ts +4 -2
  37. package/src/cli/commands/run.ts +6 -2
  38. package/src/cli/commands/types.ts +2 -2
  39. package/src/lang/codegen.test.ts +4 -1
  40. package/src/lang/core.ts +6 -4
  41. package/src/lang/dialect.test.ts +63 -0
  42. package/src/lang/dialect.ts +50 -0
  43. package/src/lang/emitters/ast.ts +145 -2
  44. package/src/lang/emitters/js-tests.ts +46 -37
  45. package/src/lang/emitters/js.ts +19 -2
  46. package/src/lang/features.test.ts +6 -5
  47. package/src/lang/index.ts +18 -5
  48. package/src/lang/parser-types.ts +17 -0
  49. package/src/lang/parser.test.ts +12 -6
  50. package/src/lang/parser.ts +113 -3
  51. package/src/lang/subset-invariant.test.ts +90 -0
  52. package/src/lang/transpiler.ts +8 -0
  53. package/src/lang/types.ts +18 -0
  54. package/src/lang/wasm.test.ts +8 -2
  55. package/src/linalg/linalg.test.ts +8 -2
  56. package/src/use-cases/batteries.test.ts +4 -0
  57. package/src/use-cases/local-helpers.test.ts +219 -0
  58. package/src/use-cases/timeout-overrides.test.ts +169 -0
  59. package/src/vm/atoms/batteries.ts +17 -3
  60. package/src/vm/runtime.ts +89 -4
  61. package/src/vm/vm.ts +47 -9
package/CLAUDE.md CHANGED
@@ -113,7 +113,11 @@ createAgent(source, vm) // Creates callable agent
113
113
 
114
114
  // VM
115
115
  const vm = new AgentVM(customAtoms)
116
- await vm.run(ast, args, { fuel, capabilities, timeoutMs, trace })
116
+ await vm.run(ast, args, {
117
+ fuel, capabilities, timeoutMs, trace,
118
+ costOverrides: { atomOp: 5 }, // per-atom fuel cost override
119
+ timeoutOverrides: { atomOp: 60_000 }, // per-atom wall-clock override (ms; 0 disables)
120
+ })
117
121
 
118
122
  // Builder
119
123
  Agent.take(schema).varSet(...).httpFetch(...).return(schema)
@@ -208,7 +212,7 @@ fn('a', 'b') // Returns { error: 'type mismatch', ... }
208
212
  **Design Notes:**
209
213
 
210
214
  - The two steps are intentionally separate for tree-shaking (TS support is optional)
211
- - `fromTS` lives in a separate entry point (`tosijs/lang/from-ts`)
215
+ - `fromTS` lives in a separate entry point (`tjs-lang/lang/from-ts`)
212
216
  - Import only what you need to keep bundle size minimal
213
217
  - Each step is independently testable (see `src/lang/codegen.test.ts`)
214
218
  - Constrained generics (`<T extends { id: number }>`) use the constraint as the example value instead of `any`
@@ -249,7 +253,7 @@ AJS expressions behave differently from JavaScript in several important ways:
249
253
  - Unit tests alongside source files (`*.test.ts`)
250
254
  - Integration tests in `src/use-cases/` (RAG, orchestration, malicious actors)
251
255
  - Security tests in `src/use-cases/malicious-actor.test.ts`
252
- - Language tests split across 17 files in `src/lang/` (lang.test.ts, features.test.ts, codegen.test.ts, parser.test.ts, from-ts.test.ts, wasm.test.ts, etc.)
256
+ - 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
257
  - 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
258
 
255
259
  Coverage targets: 98% lines on `src/vm/runtime.ts` (security-critical), 80%+ overall.
@@ -303,6 +307,7 @@ Full syntax documentation is in [`CLAUDE-TJS-SYNTAX.md`](CLAUDE-TJS-SYNTAX.md).
303
307
  - **Return types**: `function add(a: 0, b: 0): 0 { ... }` (colon syntax, same as TypeScript)
304
308
  - **Safety markers**: `!` = unsafe (skip validation), `?` = safe (explicit validation)
305
309
  - **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).
310
+ - **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
311
  - **Bang access**: `x!.foo` — returns MonadicError if `x` is null/undefined, otherwise bare `x.foo`. Chains propagate: `x!.foo!.bar`.
307
312
  - **Type/Generic/FunctionPredicate**: Three declaration forms for runtime type predicates
308
313
  - **`const!`**: Compile-time immutability, zero runtime cost
@@ -478,6 +483,7 @@ The CLI (`bun src/cli/tjs.ts run`) does NOT inject the test-block `expect` harne
478
483
 
479
484
  ### Additional Documentation
480
485
 
486
+ - `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
487
  - `llms.txt` — agent-facing navigation index (ships in npm bundle); points to docs and source entry points
482
488
  - `guides/footguns.md` — JS footguns TJS fixes (boxed-primitive truthiness, `==` coercion, `typeof null`, uninitialized `let`, etc.). Demo: `examples/js-footguns-fixed.tjs`.
483
489
  - `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.
@@ -448,9 +448,13 @@ describe('Playground Examples', () => {
448
448
  args.imageUrl = '/test-shapes.jpg'
449
449
  }
450
450
 
451
- // Use the SAME capabilities as the playground
451
+ // Use the SAME capabilities as the playground.
452
+ // Vision inference on a local model can take a while; give it an
453
+ // explicit budget well above the slow-atom timeout so the test is
454
+ // deterministic regardless of the run-level default.
452
455
  const runResult = await vm.run(result.ast, args, {
453
456
  fuel: 100000,
457
+ timeoutMs: 180000,
454
458
  capabilities: {
455
459
  fetch: httpFetch,
456
460
  llm: llmCapability || mockLLM,
@@ -466,7 +470,7 @@ describe('Playground Examples', () => {
466
470
  } finally {
467
471
  trackTestEnd()
468
472
  }
469
- }, 120000)
473
+ }, 240000) // bun-test timeout above the vm timeoutMs (180s) + overhead
470
474
  } else if (needsRetry) {
471
475
  // Examples that use runCode need retry due to LLM variability
472
476
  it(`${example.name} - runs successfully`, async () => {
@@ -255,28 +255,36 @@ export function renderConsoleMessages(
255
255
 
256
256
  /**
257
257
  * Render test results HTML with clickable error links and editor gutter markers.
258
- * Returns pass/fail counts so callers can update tab indicators.
258
+ * Returns pass/fail/inconclusive counts so callers can update tab indicators.
259
259
  */
260
260
  export function renderTestResults(
261
261
  tests: any[],
262
262
  outputEl: HTMLElement,
263
263
  editor: CodeMirror,
264
264
  goToLine: (line: number) => void
265
- ): { passed: number; failed: number } {
265
+ ): { passed: number; failed: number; inconclusive: number } {
266
266
  if (!tests || tests.length === 0) {
267
267
  outputEl.textContent = 'No tests defined'
268
268
  editor.clearMarkers()
269
- return { passed: 0, failed: 0 }
269
+ return { passed: 0, failed: 0, inconclusive: 0 }
270
270
  }
271
271
 
272
272
  const passed = tests.filter((t: any) => t.passed).length
273
- const failed = tests.filter((t: any) => !t.passed).length
274
-
275
- // Mark only FAILED tests in the editor. Passing tests appear in the
276
- // results panel and don't need an underline `severity: 'info'` was
277
- // rendering as a grey squiggle on every passing test's line, which is
278
- // visual noise.
279
- const failedWithLines = tests.filter((t: any) => t.line && !t.passed)
273
+ // Inconclusive = the test couldn't *run* (e.g. it calls an AJS atom that
274
+ // doesn't exist at build time). It is neither pass nor fail — surface it as
275
+ // a distinct warning state and keep it out of the failure count, so legal
276
+ // AJS doesn't read as broken in the playground. See PRINCIPLES.md.
277
+ const inconclusive = tests.filter(
278
+ (t: any) => !t.passed && t.inconclusive
279
+ ).length
280
+ const failed = tests.filter((t: any) => !t.passed && !t.inconclusive).length
281
+
282
+ // Mark only genuine FAILURES in the editor. Passing tests don't need an
283
+ // underline (it reads as visual noise), and an inconclusive test isn't a
284
+ // failure — a red squiggle would wrongly imply the code is broken.
285
+ const failedWithLines = tests.filter(
286
+ (t: any) => t.line && !t.passed && !t.inconclusive
287
+ )
280
288
  if (failedWithLines.length > 0) {
281
289
  editor.setMarkers(
282
290
  failedWithLines.map((t: any) => ({
@@ -294,19 +302,29 @@ export function renderTestResults(
294
302
  if (failed > 0) {
295
303
  html += `, <strong class="test-failed">${failed} failed</strong>`
296
304
  }
305
+ if (inconclusive > 0) {
306
+ html += `, <strong class="test-inconclusive">${inconclusive} inconclusive</strong>`
307
+ }
297
308
  html += `</div><ul class="test-list">`
298
309
 
299
310
  for (const test of tests) {
300
- const icon = test.passed ? '✓' : '✗'
301
- const cls = test.passed ? 'test-pass' : 'test-fail'
311
+ const state = test.passed
312
+ ? 'pass'
313
+ : test.inconclusive
314
+ ? 'inconclusive'
315
+ : 'fail'
316
+ const icon = test.passed ? '✓' : test.inconclusive ? '—' : '✗'
302
317
  const sigBadge = test.isSignatureTest
303
318
  ? ' <span class="sig-badge">signature</span>'
304
319
  : ''
305
320
  const dataLine = test.line ? ` data-line="${test.line}"` : ''
306
321
  const clickable = test.line ? ' clickable-test' : ''
307
- html += `<li class="${cls}${clickable}"${dataLine}>${icon} ${test.description}${sigBadge}`
308
- if (!test.passed && test.error) {
309
- html += `<div class="test-error">${test.error}</div>`
322
+ html += `<li class="test-${state}${clickable}"${dataLine}>${icon} ${test.description}${sigBadge}`
323
+ if (test.error) {
324
+ // Inconclusive notes are warnings (couldn't run), not failures.
325
+ const noteCls = test.inconclusive ? 'test-note' : 'test-error'
326
+ const prefix = test.inconclusive ? 'could not run — ' : ''
327
+ html += `<div class="${noteCls}">${prefix}${test.error}</div>`
310
328
  }
311
329
  html += `</li>`
312
330
  }
@@ -327,7 +345,7 @@ export function renderTestResults(
327
345
  })
328
346
  })
329
347
 
330
- return { passed, failed }
348
+ return { passed, failed, inconclusive }
331
349
  }
332
350
 
333
351
  // ---------------------------------------------------------------------------
@@ -589,6 +607,20 @@ export const sharedPlaygroundStyles: Record<string, Record<string, string>> = {
589
607
  fontFamily: 'var(--font-mono, monospace)',
590
608
  },
591
609
 
610
+ ':host .test-inconclusive': {
611
+ color: '#d97706',
612
+ },
613
+
614
+ ':host .test-note': {
615
+ marginLeft: '20px',
616
+ marginTop: '4px',
617
+ padding: '8px',
618
+ background: 'rgba(217, 119, 6, 0.1)',
619
+ borderRadius: '4px',
620
+ fontSize: '13px',
621
+ fontFamily: 'var(--font-mono, monospace)',
622
+ },
623
+
592
624
  ':host .clickable-test': {
593
625
  cursor: 'pointer',
594
626
  },
@@ -0,0 +1,112 @@
1
+ import { describe, it, expect, beforeAll, afterAll } from 'bun:test'
2
+ import { GlobalRegistrator } from '@happy-dom/global-registrator'
3
+
4
+ beforeAll(() => GlobalRegistrator.register())
5
+ afterAll(() => GlobalRegistrator.unregister())
6
+
7
+ // Imported after DOM globals exist.
8
+ const { renderTestResults } = await import('./playground-shared')
9
+
10
+ function fakeEditor() {
11
+ const calls: any[] = []
12
+ return {
13
+ setMarkers: (m: any) => calls.push({ setMarkers: m }),
14
+ clearMarkers: () => calls.push({ clearMarkers: true }),
15
+ _calls: calls,
16
+ } as any
17
+ }
18
+
19
+ describe('renderTestResults — inconclusive affordance', () => {
20
+ it('separates inconclusive from passed and failed', () => {
21
+ const out = document.createElement('div')
22
+ const editor = fakeEditor()
23
+ const counts = renderTestResults(
24
+ [
25
+ { description: 'a', passed: true },
26
+ { description: 'b', passed: false, error: 'Expected 5 got 6' },
27
+ {
28
+ description: 'c signature example',
29
+ passed: false,
30
+ inconclusive: true,
31
+ isSignatureTest: true,
32
+ error: 'httpFetch is not defined',
33
+ },
34
+ ],
35
+ out,
36
+ editor,
37
+ () => {}
38
+ )
39
+
40
+ expect(counts).toEqual({ passed: 1, failed: 1, inconclusive: 1 })
41
+
42
+ // Summary shows all three states
43
+ expect(out.querySelector('.test-summary')?.textContent).toContain(
44
+ '1 passed'
45
+ )
46
+ expect(out.querySelector('.test-summary')?.textContent).toContain(
47
+ '1 failed'
48
+ )
49
+ expect(out.querySelector('.test-summary')?.textContent).toContain(
50
+ '1 inconclusive'
51
+ )
52
+
53
+ // The inconclusive test renders with its own class + a warning note (not
54
+ // a red error), with the "could not run" framing.
55
+ const incLi = out.querySelector('li.test-inconclusive')
56
+ expect(incLi).not.toBeNull()
57
+ expect(incLi?.textContent).toContain('—') // not the ✗ failure icon
58
+ expect(incLi?.querySelector('.test-note')).not.toBeNull()
59
+ expect(incLi?.querySelector('.test-error')).toBeNull()
60
+ expect(incLi?.querySelector('.test-note')?.textContent).toContain(
61
+ 'could not run'
62
+ )
63
+
64
+ // The genuine failure keeps the red error box + ✗ icon.
65
+ const failLi = out.querySelector('li.test-fail')
66
+ expect(failLi?.textContent).toContain('✗')
67
+ expect(failLi?.querySelector('.test-error')).not.toBeNull()
68
+ })
69
+
70
+ it('renders REAL transpiler output: atom-calling agent → inconclusive', async () => {
71
+ // End-to-end: the transpiler emits inconclusive for an un-runnable
72
+ // signature test; the playground must render it as such (not a failure).
73
+ const { tjs } = await import('../../src/lang')
74
+ const { testResults } = tjs(
75
+ `function main(url: ''): { x: '' } {\n const x = httpFetch({ url })\n return { x }\n}`
76
+ )
77
+ const out = document.createElement('div')
78
+ const counts = renderTestResults(
79
+ testResults as any,
80
+ out,
81
+ fakeEditor(),
82
+ () => {}
83
+ )
84
+ expect(counts.failed).toBe(0)
85
+ expect(counts.inconclusive).toBe(1)
86
+ expect(out.querySelector('li.test-inconclusive')).not.toBeNull()
87
+ expect(out.querySelector('li.test-fail')).toBeNull()
88
+ })
89
+
90
+ it('does NOT put an error marker on an inconclusive test line', () => {
91
+ const out = document.createElement('div')
92
+ const editor = fakeEditor()
93
+ renderTestResults(
94
+ [
95
+ {
96
+ description: 'sig',
97
+ passed: false,
98
+ inconclusive: true,
99
+ line: 3,
100
+ error: 'atom not defined',
101
+ },
102
+ ],
103
+ out,
104
+ editor,
105
+ () => {}
106
+ )
107
+ // No setMarkers with an error for the inconclusive line; clearMarkers instead.
108
+ const markerCalls = editor._calls.filter((c: any) => c.setMarkers)
109
+ expect(markerCalls).toHaveLength(0)
110
+ expect(editor._calls.some((c: any) => c.clearMarkers)).toBe(true)
111
+ })
112
+ })
@@ -149,7 +149,7 @@ export class TJSPlayground extends Component<TJSPlaygroundParts> {
149
149
  // Split mode
150
150
  private _splitMode: null | 'code' | 'output' = null
151
151
  private _splitChannel: BroadcastChannel | null = null
152
- private _splitSessionId: string = ''
152
+ private _splitSessionId = ''
153
153
 
154
154
  // Build flags state
155
155
  private buildFlags = {
@@ -860,21 +860,27 @@ export class TJSPlayground extends Component<TJSPlaygroundParts> {
860
860
 
861
861
  private updateTestResults(result: any) {
862
862
  const tests = result.testResults
863
- const { passed, failed } = renderTestResults(
863
+ const { passed, failed, inconclusive } = renderTestResults(
864
864
  tests,
865
865
  this.parts.testsOutput,
866
866
  this.parts.tjsEditor,
867
867
  (line) => this.goToSourceLine(line)
868
868
  )
869
- this.updateTestsTabLabel(passed, failed)
869
+ this.updateTestsTabLabel(passed, failed, inconclusive)
870
870
  }
871
871
 
872
- private updateTestsTabLabel(passed: number, failed: number) {
872
+ private updateTestsTabLabel(
873
+ passed: number,
874
+ failed: number,
875
+ inconclusive = 0
876
+ ) {
873
877
  const tabs = this.parts.outputTabs
874
878
  if (!tabs) return
875
879
 
876
880
  if (failed > 0) {
877
881
  tabs.style.setProperty('--test-indicator-color', '#dc2626')
882
+ } else if (inconclusive > 0) {
883
+ tabs.style.setProperty('--test-indicator-color', '#d97706')
878
884
  } else if (passed > 0) {
879
885
  tabs.style.setProperty('--test-indicator-color', '#16a34a')
880
886
  } else {
@@ -1394,7 +1400,7 @@ export class TJSPlayground extends Component<TJSPlaygroundParts> {
1394
1400
  }
1395
1401
 
1396
1402
  // Navigate to a specific line in the source editor
1397
- goToSourceLine(line: number, column: number = 1) {
1403
+ goToSourceLine(line: number, column = 1) {
1398
1404
  this.parts.inputTabs.value = 0 // Switch to TJS tab (first tab)
1399
1405
  // Wait for tab switch and editor resize before scrolling
1400
1406
  setTimeout(() => {
@@ -0,0 +1,34 @@
1
+ export function calculate(x?: number, y?: number): any;
2
+ export namespace calculate {
3
+ namespace __tjs {
4
+ namespace params {
5
+ namespace x {
6
+ export namespace type {
7
+ let kind: string;
8
+ }
9
+ export let required: boolean;
10
+ let _default: null;
11
+ export { _default as default };
12
+ }
13
+ namespace y {
14
+ export namespace type_1 {
15
+ let kind_1: string;
16
+ export { kind_1 as kind };
17
+ }
18
+ export { type_1 as type };
19
+ let required_1: boolean;
20
+ export { required_1 as required };
21
+ let _default_1: null;
22
+ export { _default_1 as default };
23
+ }
24
+ }
25
+ namespace returns {
26
+ export namespace type_2 {
27
+ let kind_2: string;
28
+ export { kind_2 as kind };
29
+ }
30
+ export { type_2 as type };
31
+ }
32
+ let source: string;
33
+ }
34
+ }
@@ -0,0 +1,120 @@
1
+ export function add(a?: number, b?: number): any;
2
+ export namespace add {
3
+ namespace __tjs {
4
+ namespace params {
5
+ namespace a {
6
+ export namespace type {
7
+ let kind: string;
8
+ }
9
+ export let required: boolean;
10
+ let _default: null;
11
+ export { _default as default };
12
+ }
13
+ namespace b {
14
+ export namespace type_1 {
15
+ let kind_1: string;
16
+ export { kind_1 as kind };
17
+ }
18
+ export { type_1 as type };
19
+ let required_1: boolean;
20
+ export { required_1 as required };
21
+ let _default_1: null;
22
+ export { _default_1 as default };
23
+ }
24
+ }
25
+ namespace returns {
26
+ export namespace type_2 {
27
+ let kind_2: string;
28
+ export { kind_2 as kind };
29
+ }
30
+ export { type_2 as type };
31
+ }
32
+ let source: string;
33
+ }
34
+ }
35
+ export function subtract(a?: number, b?: number): any;
36
+ export namespace subtract {
37
+ export namespace __tjs_1 {
38
+ export namespace params_1 {
39
+ export namespace a_1 {
40
+ export namespace type_3 {
41
+ let kind_3: string;
42
+ export { kind_3 as kind };
43
+ }
44
+ export { type_3 as type };
45
+ let required_2: boolean;
46
+ export { required_2 as required };
47
+ let _default_2: null;
48
+ export { _default_2 as default };
49
+ }
50
+ export { a_1 as a };
51
+ export namespace b_1 {
52
+ export namespace type_4 {
53
+ let kind_4: string;
54
+ export { kind_4 as kind };
55
+ }
56
+ export { type_4 as type };
57
+ let required_3: boolean;
58
+ export { required_3 as required };
59
+ let _default_3: null;
60
+ export { _default_3 as default };
61
+ }
62
+ export { b_1 as b };
63
+ }
64
+ export { params_1 as params };
65
+ export namespace returns_1 {
66
+ export namespace type_5 {
67
+ let kind_5: string;
68
+ export { kind_5 as kind };
69
+ }
70
+ export { type_5 as type };
71
+ }
72
+ export { returns_1 as returns };
73
+ let source_1: string;
74
+ export { source_1 as source };
75
+ }
76
+ export { __tjs_1 as __tjs };
77
+ }
78
+ export function multiply(a?: number, b?: number): any;
79
+ export namespace multiply {
80
+ export namespace __tjs_2 {
81
+ export namespace params_2 {
82
+ export namespace a_2 {
83
+ export namespace type_6 {
84
+ let kind_6: string;
85
+ export { kind_6 as kind };
86
+ }
87
+ export { type_6 as type };
88
+ let required_4: boolean;
89
+ export { required_4 as required };
90
+ let _default_4: null;
91
+ export { _default_4 as default };
92
+ }
93
+ export { a_2 as a };
94
+ export namespace b_2 {
95
+ export namespace type_7 {
96
+ let kind_7: string;
97
+ export { kind_7 as kind };
98
+ }
99
+ export { type_7 as type };
100
+ let required_5: boolean;
101
+ export { required_5 as required };
102
+ let _default_5: null;
103
+ export { _default_5 as default };
104
+ }
105
+ export { b_2 as b };
106
+ }
107
+ export { params_2 as params };
108
+ export namespace returns_2 {
109
+ export namespace type_8 {
110
+ let kind_8: string;
111
+ export { kind_8 as kind };
112
+ }
113
+ export { type_8 as type };
114
+ }
115
+ export { returns_2 as returns };
116
+ let source_2: string;
117
+ export { source_2 as source };
118
+ }
119
+ export { __tjs_2 as __tjs };
120
+ }