tjs-lang 0.6.44 → 0.7.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 +85 -422
- package/README.md +15 -82
- package/bin/benchmarks.ts +7 -7
- package/bin/dev.ts +2 -1
- package/demo/autocomplete.test.ts +1 -1
- package/demo/docs.json +744 -48
- package/demo/src/demo-nav.ts +5 -5
- package/demo/src/index.ts +28 -36
- package/demo/src/module-sw.ts +1 -1
- package/demo/src/playground-shared.ts +17 -17
- package/demo/src/playground.ts +13 -1
- package/demo/src/style.ts +4 -1
- package/demo/src/tjs-playground.ts +5 -5
- package/demo/src/user-store.ts +2 -1
- package/demo/static/favicon.svg +17 -24
- package/demo/static/tosi-platform.json +9304 -0
- package/dist/index.js +158 -156
- package/dist/index.js.map +14 -13
- package/dist/scripts/compat-effect.d.ts +16 -0
- package/dist/scripts/compat-kysely.d.ts +13 -0
- package/dist/scripts/compat-radash.d.ts +13 -0
- package/dist/scripts/compat-superstruct.d.ts +13 -0
- package/dist/scripts/compat-ts-pattern.d.ts +13 -0
- package/dist/scripts/compat-zod.d.ts +12 -0
- package/dist/src/lang/emitters/from-ts.d.ts +1 -1
- package/dist/src/lang/emitters/js-tests.d.ts +4 -0
- package/dist/src/lang/emitters/js.d.ts +2 -2
- package/dist/src/lang/index.d.ts +1 -0
- package/dist/src/lang/json-schema.d.ts +40 -0
- package/dist/src/lang/parser-transforms.d.ts +14 -0
- package/dist/src/lang/runtime.d.ts +39 -6
- package/dist/src/types/Type.d.ts +5 -0
- package/dist/tjs-full.js +158 -156
- package/dist/tjs-full.js.map +14 -13
- package/dist/tjs-vm.js +44 -43
- package/dist/tjs-vm.js.map +5 -5
- package/docs/README.md +21 -20
- package/docs/WASM-QUICKSTART.md +283 -0
- package/docs/diagrams/architecture-shift.svg +117 -0
- package/docs/diagrams/compile-runtime.svg +130 -0
- package/docs/diagrams/icon-riff-1.svg +55 -0
- package/docs/diagrams/icon-riff-2.svg +62 -0
- package/docs/diagrams/icon-riff-3.svg +61 -0
- package/docs/diagrams/platform-overview.svg +114 -0
- package/docs/diagrams/safe-eval.svg +147 -0
- package/docs/eval-v4/arch-comparison.svg +277 -0
- package/docs/eval-v4/bundler-tree.svg +250 -0
- package/docs/eval-v4/http-lifecycle.svg +148 -0
- package/docs/function-predicate-design.md +8 -8
- package/docs/native-engine-integration.md +2 -2
- package/editors/codemirror/autocomplete.test.ts +29 -29
- package/package.json +10 -4
- package/src/cli/commands/convert.test.ts +11 -8
- package/src/cli/tjs.ts +1 -1
- package/src/lang/codegen.test.ts +117 -112
- package/src/lang/docs.test.ts +22 -22
- package/src/lang/docs.ts +5 -8
- package/src/lang/emitters/dts.test.ts +13 -13
- package/src/lang/emitters/from-ts.ts +36 -9
- package/src/lang/emitters/js-tests.ts +143 -28
- package/src/lang/emitters/js.ts +49 -28
- package/src/lang/features.test.ts +259 -43
- package/src/lang/from-ts.test.ts +3 -3
- package/src/lang/function-predicate.test.ts +1 -1
- package/src/lang/index.ts +8 -47
- package/src/lang/json-schema.test.ts +261 -0
- package/src/lang/json-schema.ts +167 -0
- package/src/lang/parser-params.ts +28 -44
- package/src/lang/parser-transforms.ts +255 -0
- package/src/lang/parser.test.ts +32 -13
- package/src/lang/parser.ts +49 -11
- package/src/lang/perf.test.ts +11 -11
- package/src/lang/roundtrip.test.ts +3 -3
- package/src/lang/runtime.test.ts +167 -0
- package/src/lang/runtime.ts +234 -46
- package/src/lang/transpiler.test.ts +21 -21
- package/src/lang/typescript-syntax.test.ts +11 -9
- package/src/types/Type.ts +38 -1
- package/src/use-cases/bootstrap.test.ts +7 -7
- package/src/use-cases/client-server.test.ts +1 -1
- package/src/use-cases/malicious-actor.test.ts +1 -1
- package/src/use-cases/rag-processor.test.ts +1 -1
- package/src/use-cases/sophisticated-agents.test.ts +2 -2
- package/src/use-cases/transpiler-llm.test.ts +1 -1
- package/src/use-cases/unbundled-imports.test.ts +9 -9
- package/tjs-lang.svg +17 -25
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 850 500"
|
|
2
|
+
font-family="system-ui, -apple-system, sans-serif">
|
|
3
|
+
<style>
|
|
4
|
+
/* Palette and semantic classes */
|
|
5
|
+
.bg { fill: #fafafa; stroke: #e4e4e4; }
|
|
6
|
+
|
|
7
|
+
/* Box styles */
|
|
8
|
+
.box-client { fill: #eef6ff; stroke: #3da8f4; stroke-width: 2; }
|
|
9
|
+
.box-process { fill: #f5f5f5; stroke: #9e9e9e; stroke-width: 2; }
|
|
10
|
+
.box-database { fill: #f0fff5; stroke: #006736; stroke-width: 2; }
|
|
11
|
+
|
|
12
|
+
/* Arrows */
|
|
13
|
+
.arrow-forward { stroke: #3da8f4; stroke-width: 2; fill: none; }
|
|
14
|
+
.arrow-return { stroke: #ff9800; stroke-width: 2; fill: none; stroke-dasharray: 4,4; }
|
|
15
|
+
|
|
16
|
+
/* Text */
|
|
17
|
+
.text-primary { fill: #181340; font-size: 13px; font-weight: 500; }
|
|
18
|
+
.text-small { fill: #9e9e9e; font-size: 11px; }
|
|
19
|
+
.text-label { fill: #181340; font-size: 12px; }
|
|
20
|
+
|
|
21
|
+
/* Title */
|
|
22
|
+
.title { fill: #181340; font-size: 18px; font-weight: 600; }
|
|
23
|
+
</style>
|
|
24
|
+
|
|
25
|
+
<defs>
|
|
26
|
+
<!-- Forward flow arrow marker (blue) -->
|
|
27
|
+
<marker id="arr-forward" viewBox="0 0 10 10" refX="9" refY="5"
|
|
28
|
+
markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
|
29
|
+
<path d="M0 0 L10 5 L0 10z" fill="#3da8f4"/>
|
|
30
|
+
</marker>
|
|
31
|
+
<!-- Return flow arrow marker (orange) -->
|
|
32
|
+
<marker id="arr-return" viewBox="0 0 10 10" refX="9" refY="5"
|
|
33
|
+
markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
|
34
|
+
<path d="M0 0 L10 5 L0 10z" fill="#ff9800"/>
|
|
35
|
+
</marker>
|
|
36
|
+
</defs>
|
|
37
|
+
|
|
38
|
+
<!-- Title -->
|
|
39
|
+
<text x="425" y="30" class="title" text-anchor="middle">HTTP Request Lifecycle</text>
|
|
40
|
+
|
|
41
|
+
<!-- ============ FORWARD REQUEST FLOW ============ -->
|
|
42
|
+
<g id="section-forward-flow" class="section">
|
|
43
|
+
|
|
44
|
+
<!-- Node: Client -->
|
|
45
|
+
<g id="node-client" class="node">
|
|
46
|
+
<rect x="50" y="70" width="120" height="40" class="box-client" rx="4"/>
|
|
47
|
+
<!-- text_y = 70 + (40/2) + (13 * 0.35) = 70 + 20 + 4.55 = 94.55 → 95 -->
|
|
48
|
+
<text x="110" y="95" class="text-primary" text-anchor="middle">Client</text>
|
|
49
|
+
</g>
|
|
50
|
+
|
|
51
|
+
<!-- Arrow: Client → DNS -->
|
|
52
|
+
<line x1="170" y1="90" x2="220" y2="90" class="arrow-forward" marker-end="url(#arr-forward)"/>
|
|
53
|
+
<text x="195" y="83" class="text-small" text-anchor="middle">sends request</text>
|
|
54
|
+
|
|
55
|
+
<!-- Node: DNS Lookup -->
|
|
56
|
+
<g id="node-dns" class="node">
|
|
57
|
+
<rect x="220" y="70" width="140" height="40" class="box-process" rx="4"/>
|
|
58
|
+
<!-- text_y = 220 + (40/2) + (13 * 0.35) = 220 + 20 + 4.55 = 244.55 → 245 -->
|
|
59
|
+
<text x="290" y="95" class="text-primary" text-anchor="middle">DNS Lookup</text>
|
|
60
|
+
</g>
|
|
61
|
+
|
|
62
|
+
<!-- Arrow: DNS → Server -->
|
|
63
|
+
<line x1="360" y1="90" x2="410" y2="90" class="arrow-forward" marker-end="url(#arr-forward)"/>
|
|
64
|
+
<text x="385" y="83" class="text-small" text-anchor="middle">resolves IP</text>
|
|
65
|
+
|
|
66
|
+
<!-- Node: Server Processing -->
|
|
67
|
+
<g id="node-server" class="node">
|
|
68
|
+
<rect x="410" y="70" width="150" height="40" class="box-process" rx="4"/>
|
|
69
|
+
<!-- text_y = 410 + (40/2) + (13 * 0.35) = 410 + 20 + 4.55 = 434.55 → 435 -->
|
|
70
|
+
<text x="485" y="95" class="text-primary" text-anchor="middle">Server Processing</text>
|
|
71
|
+
</g>
|
|
72
|
+
|
|
73
|
+
<!-- Arrow: Server → Database -->
|
|
74
|
+
<line x1="560" y1="90" x2="610" y2="90" class="arrow-forward" marker-end="url(#arr-forward)"/>
|
|
75
|
+
<text x="585" y="83" class="text-small" text-anchor="middle">query</text>
|
|
76
|
+
|
|
77
|
+
<!-- Node: Database Query -->
|
|
78
|
+
<g id="node-database" class="node">
|
|
79
|
+
<rect x="610" y="70" width="140" height="40" class="box-database" rx="4"/>
|
|
80
|
+
<!-- text_y = 610 + (40/2) + (13 * 0.35) = 610 + 20 + 4.55 = 634.55 → 635 -->
|
|
81
|
+
<text x="680" y="95" class="text-primary" text-anchor="middle">Database Query</text>
|
|
82
|
+
</g>
|
|
83
|
+
|
|
84
|
+
</g>
|
|
85
|
+
|
|
86
|
+
<!-- ============ RETURN RESPONSE FLOW (separate row) ============ -->
|
|
87
|
+
<g id="section-return-flow" class="section">
|
|
88
|
+
|
|
89
|
+
<!-- Vertical connectors: each node drops down -->
|
|
90
|
+
<line x1="110" y1="110" x2="110" y2="280" class="arrow-return" stroke-dasharray="2,2"/>
|
|
91
|
+
<line x1="290" y1="110" x2="290" y2="280" class="arrow-return" stroke-dasharray="2,2"/>
|
|
92
|
+
<line x1="485" y1="110" x2="485" y2="280" class="arrow-return" stroke-dasharray="2,2"/>
|
|
93
|
+
<line x1="680" y1="110" x2="680" y2="280" class="arrow-return" stroke-dasharray="2,2"/>
|
|
94
|
+
|
|
95
|
+
<!-- Return row with separate response path -->
|
|
96
|
+
<!-- Node: Database Response -->
|
|
97
|
+
<g id="node-db-response" class="node">
|
|
98
|
+
<rect x="630" y="280" width="100" height="40" class="box-database" rx="4"/>
|
|
99
|
+
<!-- text_y = 630 + (40/2) + (13 * 0.35) = 630 + 20 + 4.55 = 654.55 → 655 -->
|
|
100
|
+
<text x="680" y="305" class="text-primary" text-anchor="middle">Data Ready</text>
|
|
101
|
+
</g>
|
|
102
|
+
|
|
103
|
+
<!-- Arrow: DB Response → Server Response -->
|
|
104
|
+
<line x1="630" y1="300" x2="560" y2="300" class="arrow-return" marker-end="url(#arr-return)"/>
|
|
105
|
+
<text x="595" y="315" class="text-small" text-anchor="middle">returns data</text>
|
|
106
|
+
|
|
107
|
+
<!-- Node: Server Response -->
|
|
108
|
+
<g id="node-server-response" class="node">
|
|
109
|
+
<rect x="430" y="280" width="110" height="40" class="box-process" rx="4"/>
|
|
110
|
+
<!-- text_y = 430 + (40/2) + (13 * 0.35) = 430 + 20 + 4.55 = 454.55 → 455 -->
|
|
111
|
+
<text x="485" y="305" class="text-primary" text-anchor="middle">Builds Response</text>
|
|
112
|
+
</g>
|
|
113
|
+
|
|
114
|
+
<!-- Arrow: Server Response → Client Response -->
|
|
115
|
+
<line x1="430" y1="300" x2="170" y2="300" class="arrow-return" marker-end="url(#arr-return)"/>
|
|
116
|
+
<text x="300" y="315" class="text-small" text-anchor="middle">HTTP response</text>
|
|
117
|
+
|
|
118
|
+
<!-- Node: Client Receives -->
|
|
119
|
+
<g id="node-client-response" class="node">
|
|
120
|
+
<rect x="50" y="280" width="120" height="40" class="box-client" rx="4"/>
|
|
121
|
+
<!-- text_y = 50 + (40/2) + (13 * 0.35) = 50 + 20 + 4.55 = 74.55 → 75 -->
|
|
122
|
+
<text x="110" y="305" class="text-primary" text-anchor="middle">Response Ready</text>
|
|
123
|
+
</g>
|
|
124
|
+
|
|
125
|
+
</g>
|
|
126
|
+
|
|
127
|
+
<!-- ============ LEGEND ============ -->
|
|
128
|
+
<g id="legend">
|
|
129
|
+
<!-- Forward flow legend -->
|
|
130
|
+
<line x1="50" y1="390" x2="90" y2="390" class="arrow-forward" marker-end="url(#arr-forward)"/>
|
|
131
|
+
<text x="100" y="395" class="text-label">Forward flow (request)</text>
|
|
132
|
+
|
|
133
|
+
<!-- Return flow legend -->
|
|
134
|
+
<line x1="380" y1="390" x2="420" y2="390" class="arrow-return" marker-end="url(#arr-return)"/>
|
|
135
|
+
<text x="430" y="395" class="text-label">Return flow (response)</text>
|
|
136
|
+
</g>
|
|
137
|
+
|
|
138
|
+
<!-- ============ ANNOTATIONS ============ -->
|
|
139
|
+
<g id="annotations">
|
|
140
|
+
<text x="425" y="450" class="text-small" text-anchor="middle">
|
|
141
|
+
The HTTP lifecycle involves a request traveling through DNS and server processing,
|
|
142
|
+
</text>
|
|
143
|
+
<text x="425" y="465" class="text-small" text-anchor="middle">
|
|
144
|
+
querying the database, and returning a response through the same infrastructure.
|
|
145
|
+
</text>
|
|
146
|
+
</g>
|
|
147
|
+
|
|
148
|
+
</svg>
|
|
@@ -20,20 +20,20 @@ signature." Currently:
|
|
|
20
20
|
just like `0` means "integer" and `''` means "string"
|
|
21
21
|
2. **FunctionPredicate should work like Type/Generic** — same pattern of
|
|
22
22
|
predicate-based checking, introspection via metadata
|
|
23
|
-
3. **The return contract is part of the type** —
|
|
23
|
+
3. **The return contract is part of the type** — `:`, `:?`, and `:!` are
|
|
24
24
|
meaningful distinctions in the function's contract
|
|
25
25
|
|
|
26
26
|
## The Three Return Contracts
|
|
27
27
|
|
|
28
28
|
| Marker | Name | Meaning |
|
|
29
29
|
|--------|------|---------|
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
-
|
|
|
30
|
+
| `:` | `returns` | Verified at transpile time (signature test) |
|
|
31
|
+
| `:?` | `checkedReturns` | Verified at transpile time AND runtime |
|
|
32
|
+
| `:!` | `assertReturns` | Declared but not verified (metadata only) |
|
|
33
33
|
|
|
34
34
|
These are not just build options — they describe the **trust level** of
|
|
35
|
-
the function's return type. A function with
|
|
36
|
-
than one with
|
|
35
|
+
the function's return type. A function with `:?` makes a stronger promise
|
|
36
|
+
than one with `:!`.
|
|
37
37
|
|
|
38
38
|
## Syntax: Function as Type Example
|
|
39
39
|
|
|
@@ -41,7 +41,7 @@ The most TJS-idiomatic approach — a function IS its own type:
|
|
|
41
41
|
|
|
42
42
|
```tjs
|
|
43
43
|
// This function's signature IS a type
|
|
44
|
-
function formatter(input: '', options: { locale: 'en' })
|
|
44
|
+
function formatter(input: '', options: { locale: 'en' }):? '' {
|
|
45
45
|
return input
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -91,7 +91,7 @@ FunctionPredicate Callback {
|
|
|
91
91
|
Create a type from an existing function's metadata:
|
|
92
92
|
|
|
93
93
|
```tjs
|
|
94
|
-
function myFormatter(input: '', options: { locale: 'en' })
|
|
94
|
+
function myFormatter(input: '', options: { locale: 'en' }):? '' {
|
|
95
95
|
return input
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -119,7 +119,7 @@ TJS's syntax extensions are modest. The engine changes would be:
|
|
|
119
119
|
|
|
120
120
|
### Lexer
|
|
121
121
|
- Recognize `:` in parameter context (already a valid token, just needs context-sensitive handling)
|
|
122
|
-
-
|
|
122
|
+
- `:` for return types uses context-sensitive handling (already a valid token)
|
|
123
123
|
- `Type`, `Generic`, `Union`, `Enum` as contextual keywords
|
|
124
124
|
- `extend` as contextual keyword
|
|
125
125
|
- `wasm` as contextual keyword
|
|
@@ -127,7 +127,7 @@ TJS's syntax extensions are modest. The engine changes would be:
|
|
|
127
127
|
|
|
128
128
|
### Parser
|
|
129
129
|
- Desugar `:` params to `=` defaults (same as transpiler does today)
|
|
130
|
-
- Desugar
|
|
130
|
+
- Desugar `:` return annotations to metadata
|
|
131
131
|
- Desugar `Type`/`Generic`/`Union`/`Enum` declarations to `const` + function calls
|
|
132
132
|
- Desugar `extend` blocks to `.call()` rewriting
|
|
133
133
|
- Desugar `wasm {}` blocks (or hand off to WASM compiler)
|
|
@@ -58,48 +58,48 @@ function getObjectBeforeDot(source: string, dotPos: number): string | null {
|
|
|
58
58
|
// Curated property completions (simplified version of ajs-language.ts)
|
|
59
59
|
const PROPERTY_COMPLETIONS: Record<string, Completion[]> = {
|
|
60
60
|
console: [
|
|
61
|
-
{ label: 'log', type: 'method', detail: '(...args: any[])
|
|
62
|
-
{ label: 'error', type: 'method', detail: '(...args: any[])
|
|
63
|
-
{ label: 'warn', type: 'method', detail: '(...args: any[])
|
|
64
|
-
{ label: 'info', type: 'method', detail: '(...args: any[])
|
|
65
|
-
{ label: 'debug', type: 'method', detail: '(...args: any[])
|
|
66
|
-
{ label: 'table', type: 'method', detail: '(data: any)
|
|
67
|
-
{ label: 'clear', type: 'method', detail: '()
|
|
61
|
+
{ label: 'log', type: 'method', detail: '(...args: any[]): void' },
|
|
62
|
+
{ label: 'error', type: 'method', detail: '(...args: any[]): void' },
|
|
63
|
+
{ label: 'warn', type: 'method', detail: '(...args: any[]): void' },
|
|
64
|
+
{ label: 'info', type: 'method', detail: '(...args: any[]): void' },
|
|
65
|
+
{ label: 'debug', type: 'method', detail: '(...args: any[]): void' },
|
|
66
|
+
{ label: 'table', type: 'method', detail: '(data: any): void' },
|
|
67
|
+
{ label: 'clear', type: 'method', detail: '(): void' },
|
|
68
68
|
],
|
|
69
69
|
Math: [
|
|
70
|
-
{ label: 'floor', type: 'method', detail: '(x: number)
|
|
71
|
-
{ label: 'ceil', type: 'method', detail: '(x: number)
|
|
72
|
-
{ label: 'round', type: 'method', detail: '(x: number)
|
|
73
|
-
{ label: 'abs', type: 'method', detail: '(x: number)
|
|
74
|
-
{ label: 'min', type: 'method', detail: '(...values: number[])
|
|
75
|
-
{ label: 'max', type: 'method', detail: '(...values: number[])
|
|
76
|
-
{ label: 'sqrt', type: 'method', detail: '(x: number)
|
|
77
|
-
{ label: 'pow', type: 'method', detail: '(base, exp)
|
|
78
|
-
{ label: 'random', type: 'method', detail: '()
|
|
70
|
+
{ label: 'floor', type: 'method', detail: '(x: number): number' },
|
|
71
|
+
{ label: 'ceil', type: 'method', detail: '(x: number): number' },
|
|
72
|
+
{ label: 'round', type: 'method', detail: '(x: number): number' },
|
|
73
|
+
{ label: 'abs', type: 'method', detail: '(x: number): number' },
|
|
74
|
+
{ label: 'min', type: 'method', detail: '(...values: number[]): number' },
|
|
75
|
+
{ label: 'max', type: 'method', detail: '(...values: number[]): number' },
|
|
76
|
+
{ label: 'sqrt', type: 'method', detail: '(x: number): number' },
|
|
77
|
+
{ label: 'pow', type: 'method', detail: '(base, exp): number' },
|
|
78
|
+
{ label: 'random', type: 'method', detail: '(): number' },
|
|
79
79
|
{ label: 'PI', type: 'property', detail: 'number' },
|
|
80
80
|
{ label: 'E', type: 'property', detail: 'number' },
|
|
81
81
|
],
|
|
82
82
|
JSON: [
|
|
83
|
-
{ label: 'parse', type: 'method', detail: '(text: string)
|
|
84
|
-
{ label: 'stringify', type: 'method', detail: '(value: any)
|
|
83
|
+
{ label: 'parse', type: 'method', detail: '(text: string): any' },
|
|
84
|
+
{ label: 'stringify', type: 'method', detail: '(value: any): string' },
|
|
85
85
|
],
|
|
86
86
|
Object: [
|
|
87
|
-
{ label: 'keys', type: 'method', detail: '(obj: object)
|
|
88
|
-
{ label: 'values', type: 'method', detail: '(obj: object)
|
|
87
|
+
{ label: 'keys', type: 'method', detail: '(obj: object): string[]' },
|
|
88
|
+
{ label: 'values', type: 'method', detail: '(obj: object): any[]' },
|
|
89
89
|
{
|
|
90
90
|
label: 'entries',
|
|
91
91
|
type: 'method',
|
|
92
|
-
detail: '(obj: object)
|
|
92
|
+
detail: '(obj: object): [string, any][]',
|
|
93
93
|
},
|
|
94
94
|
{
|
|
95
95
|
label: 'assign',
|
|
96
96
|
type: 'method',
|
|
97
|
-
detail: '(target, ...sources)
|
|
97
|
+
detail: '(target, ...sources): object',
|
|
98
98
|
},
|
|
99
99
|
],
|
|
100
100
|
Array: [
|
|
101
|
-
{ label: 'isArray', type: 'method', detail: '(value: any)
|
|
102
|
-
{ label: 'from', type: 'method', detail: '(iterable)
|
|
101
|
+
{ label: 'isArray', type: 'method', detail: '(value: any): boolean' },
|
|
102
|
+
{ label: 'from', type: 'method', detail: '(iterable): any[]' },
|
|
103
103
|
],
|
|
104
104
|
}
|
|
105
105
|
|
|
@@ -220,7 +220,7 @@ function getCompletions(ctx: CompletionContext): Completion[] {
|
|
|
220
220
|
completions.push({
|
|
221
221
|
label: metadata.name,
|
|
222
222
|
type: 'function',
|
|
223
|
-
detail: `(${params})
|
|
223
|
+
detail: `(${params}): ${returnType}`,
|
|
224
224
|
})
|
|
225
225
|
}
|
|
226
226
|
}
|
|
@@ -260,7 +260,7 @@ describe('Autocomplete', () => {
|
|
|
260
260
|
|
|
261
261
|
describe('Return type context (after ->)', () => {
|
|
262
262
|
it('suggests types after arrow', () => {
|
|
263
|
-
const { source, position } = parseSource('function foo(x: 0)
|
|
263
|
+
const { source, position } = parseSource('function foo(x: 0): |')
|
|
264
264
|
const completions = getCompletions({ source, position })
|
|
265
265
|
|
|
266
266
|
expect(completions.some((c) => c.label === '{}')).toBe(true)
|
|
@@ -425,7 +425,7 @@ const after = 2
|
|
|
425
425
|
|
|
426
426
|
describe('With transpiled metadata', () => {
|
|
427
427
|
it('extracts function signature from transpiled code', () => {
|
|
428
|
-
const source = `function add(a: 0, b: 0)
|
|
428
|
+
const source = `function add(a: 0, b: 0): 0 {
|
|
429
429
|
return a + b
|
|
430
430
|
}`
|
|
431
431
|
const metadata = getMetadata(source)
|
|
@@ -437,7 +437,7 @@ const after = 2
|
|
|
437
437
|
})
|
|
438
438
|
|
|
439
439
|
it('extracts example-based types', () => {
|
|
440
|
-
const source = `function greet(name: 'World', times = 1)
|
|
440
|
+
const source = `function greet(name: 'World', times = 1):! '' {
|
|
441
441
|
return 'Hello ' + name
|
|
442
442
|
}`
|
|
443
443
|
const metadata = getMetadata(source)
|
|
@@ -450,7 +450,7 @@ const after = 2
|
|
|
450
450
|
})
|
|
451
451
|
|
|
452
452
|
it('handles object return types', () => {
|
|
453
|
-
const source = `function createUser(name: '', age: 0)
|
|
453
|
+
const source = `function createUser(name: '', age: 0): { name: '', age: 0 } {
|
|
454
454
|
return { name, age }
|
|
455
455
|
}`
|
|
456
456
|
const metadata = getMetadata(source)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tjs-lang",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.3",
|
|
4
4
|
"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.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -21,25 +21,31 @@
|
|
|
21
21
|
],
|
|
22
22
|
"license": "Apache-2.0",
|
|
23
23
|
"main": "./dist/index.js",
|
|
24
|
+
"types": "./dist/src/index.d.ts",
|
|
24
25
|
"exports": {
|
|
25
26
|
".": {
|
|
26
27
|
"bun": "./src/index.ts",
|
|
28
|
+
"types": "./dist/src/index.d.ts",
|
|
27
29
|
"default": "./dist/index.js"
|
|
28
30
|
},
|
|
29
31
|
"./eval": {
|
|
30
32
|
"bun": "./src/lang/eval.ts",
|
|
33
|
+
"types": "./dist/src/lang/eval.d.ts",
|
|
31
34
|
"default": "./dist/lang/eval.js"
|
|
32
35
|
},
|
|
33
36
|
"./lang": {
|
|
34
37
|
"bun": "./src/lang/index.ts",
|
|
38
|
+
"types": "./dist/src/lang/index.d.ts",
|
|
35
39
|
"default": "./dist/lang/index.js"
|
|
36
40
|
},
|
|
37
41
|
"./lang/eval": {
|
|
38
42
|
"bun": "./src/lang/eval.ts",
|
|
43
|
+
"types": "./dist/src/lang/eval.d.ts",
|
|
39
44
|
"default": "./dist/lang/eval.js"
|
|
40
45
|
},
|
|
41
46
|
"./lang/from-ts": {
|
|
42
47
|
"bun": "./src/lang/emitters/from-ts.ts",
|
|
48
|
+
"types": "./dist/src/lang/emitters/from-ts.d.ts",
|
|
43
49
|
"default": "./dist/lang/emitters/from-ts.js"
|
|
44
50
|
},
|
|
45
51
|
"./src": "./src/index.ts",
|
|
@@ -94,8 +100,8 @@
|
|
|
94
100
|
"firebase-functions": "^7.0.5",
|
|
95
101
|
"marked": "^9.1.6",
|
|
96
102
|
"prettier": "^2.8.8",
|
|
97
|
-
"tosijs": "^1.
|
|
98
|
-
"tosijs-ui": "^1.
|
|
103
|
+
"tosijs": "^1.5.6",
|
|
104
|
+
"tosijs-ui": "^1.4.7",
|
|
99
105
|
"typescript": "^5.6.2",
|
|
100
106
|
"valibot": "^0.36.0",
|
|
101
107
|
"vitest": "^2.0.5"
|
|
@@ -125,6 +131,6 @@
|
|
|
125
131
|
"dependencies": {
|
|
126
132
|
"acorn": "^8.15.0",
|
|
127
133
|
"acorn-walk": "^8.3.4",
|
|
128
|
-
"tosijs-schema": "^1.
|
|
134
|
+
"tosijs-schema": "^1.3.0"
|
|
129
135
|
}
|
|
130
136
|
}
|
|
@@ -43,16 +43,18 @@ describe('tjs convert - TS to JS pipeline', () => {
|
|
|
43
43
|
|
|
44
44
|
expect(jsResult.code).toContain('function greet')
|
|
45
45
|
expect(jsResult.code).toContain('__tjs')
|
|
46
|
-
|
|
46
|
+
// TS-originated code (/* tjs <- */) gets safety 'none', so no validation
|
|
47
|
+
expect(jsResult.code).toContain('"unsafe": true')
|
|
47
48
|
})
|
|
48
49
|
|
|
49
|
-
it('
|
|
50
|
+
it('TS-originated code skips runtime validation (safety none)', () => {
|
|
50
51
|
const tjsResult = fromTS(TS_SIMPLE, { emitTJS: true })
|
|
51
52
|
const jsResult = tjs(tjsResult.code, { runTests: 'report' })
|
|
52
53
|
|
|
53
|
-
//
|
|
54
|
-
expect(jsResult.code).toContain("typeof name !== 'string'")
|
|
55
|
-
expect(jsResult.code).toContain('typeError')
|
|
54
|
+
// TS-originated code (/* tjs <- */) gets safety 'none', no type checks
|
|
55
|
+
expect(jsResult.code).not.toContain("typeof name !== 'string'")
|
|
56
|
+
expect(jsResult.code).not.toContain('typeError')
|
|
57
|
+
expect(jsResult.code).toContain('"unsafe": true')
|
|
56
58
|
})
|
|
57
59
|
|
|
58
60
|
it('includes type metadata on functions', () => {
|
|
@@ -111,7 +113,7 @@ function getAge(): number { return 30 }
|
|
|
111
113
|
it('produces TJS with return type annotations', () => {
|
|
112
114
|
const result = fromTS(TS_SIMPLE, { emitTJS: true })
|
|
113
115
|
|
|
114
|
-
expect(result.code).toContain("
|
|
116
|
+
expect(result.code).toContain(":! ''")
|
|
115
117
|
})
|
|
116
118
|
|
|
117
119
|
it('preserves inline test comments', () => {
|
|
@@ -154,7 +156,8 @@ function getAge(): number { return 30 }
|
|
|
154
156
|
|
|
155
157
|
expect(stdout).toContain('function greet')
|
|
156
158
|
expect(stdout).toContain('__tjs')
|
|
157
|
-
|
|
159
|
+
// TS-originated code gets safety 'none', so no typeError validation
|
|
160
|
+
expect(stdout).toContain('"unsafe": true')
|
|
158
161
|
})
|
|
159
162
|
|
|
160
163
|
it('converts a single TS file to TJS with --emit-tjs', async () => {
|
|
@@ -169,7 +172,7 @@ function getAge(): number { return 30 }
|
|
|
169
172
|
await proc.exited
|
|
170
173
|
|
|
171
174
|
expect(stdout).toContain("name: ''")
|
|
172
|
-
expect(stdout).toContain("
|
|
175
|
+
expect(stdout).toContain(":! ''")
|
|
173
176
|
expect(stdout).not.toContain('__tjs')
|
|
174
177
|
})
|
|
175
178
|
|
package/src/cli/tjs.ts
CHANGED