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.
- package/CLAUDE.md +70 -444
- 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 +743 -47
- 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 +176 -175
- package/dist/index.js.map +5 -43
- 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 -20
- package/dist/src/types/Type.d.ts +5 -0
- package/dist/tjs-batteries.js +3 -4
- package/dist/tjs-batteries.js.map +5 -13
- package/dist/tjs-eval.js +47 -0
- package/dist/tjs-eval.js.map +7 -0
- package/dist/tjs-from-ts.js +58 -0
- package/dist/tjs-from-ts.js.map +7 -0
- package/dist/tjs-lang.js +349 -0
- package/dist/tjs-lang.js.map +7 -0
- package/dist/tjs-vm.js +51 -51
- package/dist/tjs-vm.js.map +4 -19
- 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 +24 -12
- package/src/cli/commands/convert.test.ts +11 -8
- 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 +44 -31
- 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 +213 -64
- 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
- package/dist/tjs-full.js +0 -435
- package/dist/tjs-full.js.map +0 -45
- package/dist/tjs-transpiler.js +0 -3
- package/dist/tjs-transpiler.js.map +0 -11
package/src/lang/docs.test.ts
CHANGED
|
@@ -12,11 +12,11 @@ describe('generateDocs', () => {
|
|
|
12
12
|
describe('basic output', () => {
|
|
13
13
|
it('extracts function signatures in document order', () => {
|
|
14
14
|
const source = `
|
|
15
|
-
function first(x: 5)
|
|
15
|
+
function first(x: 5): 10 {
|
|
16
16
|
return x * 2
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
function second(a: '', b: 0)
|
|
19
|
+
function second(a: '', b: 0): '' {
|
|
20
20
|
return a + b
|
|
21
21
|
}
|
|
22
22
|
`
|
|
@@ -56,12 +56,12 @@ More docs here.
|
|
|
56
56
|
/*#
|
|
57
57
|
# First Section
|
|
58
58
|
*/
|
|
59
|
-
function first(x: 0)
|
|
59
|
+
function first(x: 0): 0 { return x }
|
|
60
60
|
|
|
61
61
|
/*#
|
|
62
62
|
# Second Section
|
|
63
63
|
*/
|
|
64
|
-
function second(x: 0)
|
|
64
|
+
function second(x: 0): 0 { return x }
|
|
65
65
|
`
|
|
66
66
|
const result = generateDocs(source)
|
|
67
67
|
|
|
@@ -77,14 +77,14 @@ function second(x: 0) -> 0 { return x }
|
|
|
77
77
|
|
|
78
78
|
describe('function signatures', () => {
|
|
79
79
|
it('captures full signature with params and return type', () => {
|
|
80
|
-
const source = `function greet(name: 'World')
|
|
80
|
+
const source = `function greet(name: 'World'): '' { return name }`
|
|
81
81
|
const result = generateDocs(source)
|
|
82
82
|
|
|
83
83
|
const func = result.items[0] as any
|
|
84
84
|
expect(func.type).toBe('function')
|
|
85
85
|
expect(func.signature).toContain('greet')
|
|
86
86
|
expect(func.signature).toContain("name: 'World'")
|
|
87
|
-
expect(func.signature).toContain("
|
|
87
|
+
expect(func.signature).toContain(": ''")
|
|
88
88
|
})
|
|
89
89
|
|
|
90
90
|
it('captures optional params with defaults', () => {
|
|
@@ -173,11 +173,11 @@ This is documentation.
|
|
|
173
173
|
})
|
|
174
174
|
|
|
175
175
|
it('renders function signatures as code blocks', () => {
|
|
176
|
-
const source = `function double(x: 5)
|
|
176
|
+
const source = `function double(x: 5): 10 { return x * 2 }`
|
|
177
177
|
const result = generateDocs(source)
|
|
178
178
|
|
|
179
179
|
expect(result.markdown).toContain('```tjs')
|
|
180
|
-
expect(result.markdown).toContain('function double(x: 5)
|
|
180
|
+
expect(result.markdown).toContain('function double(x: 5): 10')
|
|
181
181
|
expect(result.markdown).toContain('```')
|
|
182
182
|
})
|
|
183
183
|
|
|
@@ -186,11 +186,11 @@ This is documentation.
|
|
|
186
186
|
/*#
|
|
187
187
|
Intro
|
|
188
188
|
*/
|
|
189
|
-
function first(x: 0)
|
|
189
|
+
function first(x: 0): 0 { return x }
|
|
190
190
|
/*#
|
|
191
191
|
Middle
|
|
192
192
|
*/
|
|
193
|
-
function second(x: 0)
|
|
193
|
+
function second(x: 0): 0 { return x }
|
|
194
194
|
`
|
|
195
195
|
const result = generateDocs(source)
|
|
196
196
|
|
|
@@ -208,11 +208,11 @@ function second(x: 0) -> 0 { return x }
|
|
|
208
208
|
A collection of math functions.
|
|
209
209
|
*/
|
|
210
210
|
|
|
211
|
-
function double(x: 5)
|
|
211
|
+
function double(x: 5): 10 {
|
|
212
212
|
return x * 2
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
function triple(x: 3)
|
|
215
|
+
function triple(x: 3): 9 {
|
|
216
216
|
return x * 3
|
|
217
217
|
}
|
|
218
218
|
|
|
@@ -275,13 +275,13 @@ These functions are pure.
|
|
|
275
275
|
it('handles mixed TJS and TypeScript in same file', () => {
|
|
276
276
|
const source = `
|
|
277
277
|
function tsFunc(x: number): number { return x }
|
|
278
|
-
function tjsFunc(x: 0)
|
|
278
|
+
function tjsFunc(x: 0): 0 { return x }
|
|
279
279
|
`
|
|
280
280
|
const result = generateDocs(source)
|
|
281
281
|
|
|
282
282
|
expect(result.items).toHaveLength(2)
|
|
283
283
|
expect((result.items[0] as any).signature).toContain(': number')
|
|
284
|
-
expect((result.items[1] as any).signature).toContain('
|
|
284
|
+
expect((result.items[1] as any).signature).toContain(': 0')
|
|
285
285
|
})
|
|
286
286
|
})
|
|
287
287
|
})
|
|
@@ -299,7 +299,7 @@ describe('generateDocsMarkdown', () => {
|
|
|
299
299
|
})
|
|
300
300
|
|
|
301
301
|
it('renders function with type metadata', () => {
|
|
302
|
-
const source = `function greet(name: 'World')
|
|
302
|
+
const source = `function greet(name: 'World'): '' { return name }`
|
|
303
303
|
const types = {
|
|
304
304
|
greet: {
|
|
305
305
|
params: {
|
|
@@ -313,7 +313,7 @@ describe('generateDocsMarkdown', () => {
|
|
|
313
313
|
|
|
314
314
|
expect(result).toContain('## greet')
|
|
315
315
|
expect(result).toContain('```tjs')
|
|
316
|
-
expect(result).toContain("function greet(name: 'World')
|
|
316
|
+
expect(result).toContain("function greet(name: 'World'): ''")
|
|
317
317
|
expect(result).toContain('**Parameters:**')
|
|
318
318
|
expect(result).toContain('`name`: string')
|
|
319
319
|
expect(result).toContain('(e.g. `"World"`)')
|
|
@@ -341,13 +341,13 @@ describe('generateDocsMarkdown', () => {
|
|
|
341
341
|
it('works without type metadata', () => {
|
|
342
342
|
const source = `
|
|
343
343
|
/*# Intro */
|
|
344
|
-
function foo(x: 0)
|
|
344
|
+
function foo(x: 0): 0 { return x }
|
|
345
345
|
`
|
|
346
346
|
const result = generateDocsMarkdown(source, undefined)
|
|
347
347
|
|
|
348
348
|
expect(result).toContain('Intro')
|
|
349
349
|
expect(result).toContain('## foo')
|
|
350
|
-
expect(result).toContain('function foo(x: 0)
|
|
350
|
+
expect(result).toContain('function foo(x: 0): 0')
|
|
351
351
|
// No params/returns since no type metadata
|
|
352
352
|
expect(result).not.toContain('**Parameters:**')
|
|
353
353
|
})
|
|
@@ -355,9 +355,9 @@ function foo(x: 0) -> 0 { return x }
|
|
|
355
355
|
it('preserves document order with interleaved docs and functions', () => {
|
|
356
356
|
const source = `
|
|
357
357
|
/*# Section 1 */
|
|
358
|
-
function first(x: 0)
|
|
358
|
+
function first(x: 0): 0 { return x }
|
|
359
359
|
/*# Section 2 */
|
|
360
|
-
function second(x: 0)
|
|
360
|
+
function second(x: 0): 0 { return x }
|
|
361
361
|
/*# Conclusion */
|
|
362
362
|
`
|
|
363
363
|
const types = {
|
|
@@ -409,14 +409,14 @@ function greet(name: string): string {
|
|
|
409
409
|
const source = `
|
|
410
410
|
/*# Module header */
|
|
411
411
|
|
|
412
|
-
function first(x: 0)
|
|
412
|
+
function first(x: 0): 0 {
|
|
413
413
|
/*# Comment inside first - should be ignored */
|
|
414
414
|
return x
|
|
415
415
|
}
|
|
416
416
|
|
|
417
417
|
/*# Between first and second */
|
|
418
418
|
|
|
419
|
-
function second(y: '')
|
|
419
|
+
function second(y: ''): '' {
|
|
420
420
|
/*# Comment inside second - should be ignored */
|
|
421
421
|
return y
|
|
422
422
|
}
|
package/src/lang/docs.ts
CHANGED
|
@@ -67,10 +67,10 @@ export function generateDocs(source: string): DocResult {
|
|
|
67
67
|
|
|
68
68
|
// Find all doc blocks and functions, sort by position
|
|
69
69
|
const docPattern = /\/\*#([\s\S]*?)\*\//g
|
|
70
|
-
// Match
|
|
70
|
+
// Match TJS function syntax with return type annotations (:, :?, :!)
|
|
71
71
|
// Return type can be quoted string with spaces (e.g. 'Hello, World!')
|
|
72
72
|
const funcPattern =
|
|
73
|
-
/function\s+(\w+)\s*\(([^)]*)\)\s*(?:(
|
|
73
|
+
/function\s+(\w+)\s*\(([^)]*)\)\s*(?:(:[?!]?)\s*('[^']*'|"[^"]*"|[^\s{]+))?\s*\{/g
|
|
74
74
|
|
|
75
75
|
type Match = { type: 'doc' | 'function'; index: number; data: any }
|
|
76
76
|
const matches: Match[] = []
|
|
@@ -107,14 +107,11 @@ export function generateDocs(source: string): DocResult {
|
|
|
107
107
|
const name = match[1]
|
|
108
108
|
const params = match[2]
|
|
109
109
|
const returnMarker = match[3] || ''
|
|
110
|
-
const
|
|
111
|
-
const tsReturnType = match[5] || ''
|
|
110
|
+
const returnType = match[4] || ''
|
|
112
111
|
|
|
113
112
|
let signature = `function ${name}(${params})`
|
|
114
|
-
if (returnMarker) {
|
|
115
|
-
signature +=
|
|
116
|
-
} else if (tsReturnType) {
|
|
117
|
-
signature += `: ${tsReturnType}`
|
|
113
|
+
if (returnMarker && returnType) {
|
|
114
|
+
signature += `${returnMarker} ${returnType}`
|
|
118
115
|
}
|
|
119
116
|
|
|
120
117
|
matches.push({
|
|
@@ -101,7 +101,7 @@ describe('typeDescriptorToTS', () => {
|
|
|
101
101
|
describe('generateDTS', () => {
|
|
102
102
|
it('should generate declarations for exported functions', () => {
|
|
103
103
|
const source = `
|
|
104
|
-
export function greet(name: 'Alice')
|
|
104
|
+
export function greet(name: 'Alice'): '' {
|
|
105
105
|
return \`Hello, \${name}!\`
|
|
106
106
|
}
|
|
107
107
|
`
|
|
@@ -115,7 +115,7 @@ export function greet(name: 'Alice') -> '' {
|
|
|
115
115
|
|
|
116
116
|
it('should handle optional parameters', () => {
|
|
117
117
|
const source = `
|
|
118
|
-
export function greet(name = 'world')
|
|
118
|
+
export function greet(name = 'world'): '' {
|
|
119
119
|
return \`Hello, \${name}!\`
|
|
120
120
|
}
|
|
121
121
|
`
|
|
@@ -127,7 +127,7 @@ export function greet(name = 'world') -> '' {
|
|
|
127
127
|
|
|
128
128
|
it('should handle multiple parameters and return types', () => {
|
|
129
129
|
const source = `
|
|
130
|
-
export function add(a: 0, b: 0)
|
|
130
|
+
export function add(a: 0, b: 0): 0 {
|
|
131
131
|
return a + b
|
|
132
132
|
}
|
|
133
133
|
`
|
|
@@ -141,11 +141,11 @@ export function add(a: 0, b: 0) -> 0 {
|
|
|
141
141
|
|
|
142
142
|
it('should skip non-exported functions when exports exist', () => {
|
|
143
143
|
const source = `
|
|
144
|
-
function helper(x: '')
|
|
144
|
+
function helper(x: ''): '' {
|
|
145
145
|
return x.toUpperCase()
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
export function greet(name: 'Alice')
|
|
148
|
+
export function greet(name: 'Alice'): '' {
|
|
149
149
|
return helper(name)
|
|
150
150
|
}
|
|
151
151
|
`
|
|
@@ -158,7 +158,7 @@ export function greet(name: 'Alice') -> '' {
|
|
|
158
158
|
|
|
159
159
|
it('should treat all functions as exported when no exports exist', () => {
|
|
160
160
|
const source = `
|
|
161
|
-
function add(a: 0, b: 0)
|
|
161
|
+
function add(a: 0, b: 0): 0 {
|
|
162
162
|
return a + b
|
|
163
163
|
}
|
|
164
164
|
`
|
|
@@ -170,7 +170,7 @@ function add(a: 0, b: 0) -> 0 {
|
|
|
170
170
|
|
|
171
171
|
it('should handle object parameter shapes', () => {
|
|
172
172
|
const source = `
|
|
173
|
-
export function createUser(user: { name: '', age: 0 })
|
|
173
|
+
export function createUser(user: { name: '', age: 0 }): { id: 0, name: '' } {
|
|
174
174
|
return { id: 1, name: user.name }
|
|
175
175
|
}
|
|
176
176
|
`
|
|
@@ -183,7 +183,7 @@ export function createUser(user: { name: '', age: 0 }) -> { id: 0, name: '' } {
|
|
|
183
183
|
|
|
184
184
|
it('should handle nullable parameters', () => {
|
|
185
185
|
const source = `
|
|
186
|
-
export function find(id: 0 | null)
|
|
186
|
+
export function find(id: 0 | null): '' {
|
|
187
187
|
return id ? 'found' : 'not found'
|
|
188
188
|
}
|
|
189
189
|
`
|
|
@@ -213,7 +213,7 @@ export function area(w: 0.0, h: 0.0) {
|
|
|
213
213
|
it('should include JSDoc from TDoc comments', () => {
|
|
214
214
|
const source = `
|
|
215
215
|
/*# Greet a person by name */
|
|
216
|
-
function greet(name: 'Alice')
|
|
216
|
+
function greet(name: 'Alice'): '' {
|
|
217
217
|
return \`Hello, \${name}!\`
|
|
218
218
|
}
|
|
219
219
|
`
|
|
@@ -225,7 +225,7 @@ function greet(name: 'Alice') -> '' {
|
|
|
225
225
|
|
|
226
226
|
it('should wrap in module declaration when moduleName is given', () => {
|
|
227
227
|
const source = `
|
|
228
|
-
export function add(a: 0, b: 0)
|
|
228
|
+
export function add(a: 0, b: 0): 0 {
|
|
229
229
|
return a + b
|
|
230
230
|
}
|
|
231
231
|
`
|
|
@@ -239,7 +239,7 @@ export function add(a: 0, b: 0) -> 0 {
|
|
|
239
239
|
|
|
240
240
|
it('should handle array return types', () => {
|
|
241
241
|
const source = `
|
|
242
|
-
export function getNames(count: 0)
|
|
242
|
+
export function getNames(count: 0): [''] {
|
|
243
243
|
return Array(count).fill('test')
|
|
244
244
|
}
|
|
245
245
|
`
|
|
@@ -393,7 +393,7 @@ describe('generateDTS — Type declarations', () => {
|
|
|
393
393
|
const source = `
|
|
394
394
|
export Type Name = 'World'
|
|
395
395
|
|
|
396
|
-
export function greet(name: Name)
|
|
396
|
+
export function greet(name: Name): '' {
|
|
397
397
|
return \`Hello, \${name}!\`
|
|
398
398
|
}
|
|
399
399
|
`
|
|
@@ -614,7 +614,7 @@ export class Point {
|
|
|
614
614
|
}
|
|
615
615
|
}
|
|
616
616
|
|
|
617
|
-
export function greet(name: '')
|
|
617
|
+
export function greet(name: ''): '' {
|
|
618
618
|
return \`Hello, \${name}!\`
|
|
619
619
|
}
|
|
620
620
|
`
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* }
|
|
16
16
|
*
|
|
17
17
|
* // Output TJS:
|
|
18
|
-
* function greet(name: '', age = 0)
|
|
18
|
+
* function greet(name: '', age = 0): '' {
|
|
19
19
|
* return `Hello, ${name}!`
|
|
20
20
|
* }
|
|
21
21
|
*
|
|
@@ -122,8 +122,15 @@ interface TypeResolutionContext {
|
|
|
122
122
|
visited?: Set<string>
|
|
123
123
|
/** Type parameter constraints and defaults from enclosing generic function/class */
|
|
124
124
|
typeParams?: Map<string, { constraint?: ts.TypeNode; default?: ts.TypeNode }>
|
|
125
|
+
/** Cache resolved type alias/interface results to avoid redundant traversals */
|
|
126
|
+
resolvedCache?: Map<string, TypeInfo>
|
|
127
|
+
/** Current resolution depth — bail to 'any' when too deep */
|
|
128
|
+
depth?: number
|
|
125
129
|
}
|
|
126
130
|
|
|
131
|
+
/** Maximum type resolution depth before degrading to 'any' */
|
|
132
|
+
const MAX_TYPE_DEPTH = 20
|
|
133
|
+
|
|
127
134
|
/**
|
|
128
135
|
* DOM interface types — not constructible but common in TS signatures.
|
|
129
136
|
* Map to {} (opaque object) so params stay annotated and required
|
|
@@ -646,6 +653,13 @@ function typeToInfo(
|
|
|
646
653
|
): TypeInfo {
|
|
647
654
|
if (!type) return { kind: 'any' }
|
|
648
655
|
|
|
656
|
+
// Bail on deeply nested type resolution to prevent exponential traversal
|
|
657
|
+
const depth = ctx?.depth ?? 0
|
|
658
|
+
if (depth > MAX_TYPE_DEPTH) return { kind: 'any' }
|
|
659
|
+
// Increment depth for recursive calls (mutating ctx would be wrong since
|
|
660
|
+
// sibling types share the same ctx; spread creates a child scope)
|
|
661
|
+
ctx = ctx ? { ...ctx, depth: depth + 1 } : undefined
|
|
662
|
+
|
|
649
663
|
switch (type.kind) {
|
|
650
664
|
case ts.SyntaxKind.StringKeyword:
|
|
651
665
|
return { kind: 'string' }
|
|
@@ -802,17 +816,27 @@ function typeToInfo(
|
|
|
802
816
|
|
|
803
817
|
// Resolve type aliases
|
|
804
818
|
if (ctx?.typeAliases?.has(typeName)) {
|
|
819
|
+
// Check cache first
|
|
820
|
+
if (ctx.resolvedCache?.has(typeName)) {
|
|
821
|
+
return ctx.resolvedCache.get(typeName)!
|
|
822
|
+
}
|
|
805
823
|
const visited = ctx.visited ?? new Set<string>()
|
|
806
824
|
if (visited.has(typeName)) {
|
|
807
825
|
return { kind: 'any' } // Circular reference
|
|
808
826
|
}
|
|
809
827
|
visited.add(typeName)
|
|
810
828
|
const resolvedType = ctx.typeAliases.get(typeName)!
|
|
811
|
-
|
|
829
|
+
const result = typeToInfo(resolvedType, { ...ctx, visited })
|
|
830
|
+
ctx.resolvedCache?.set(typeName, result)
|
|
831
|
+
return result
|
|
812
832
|
}
|
|
813
833
|
|
|
814
834
|
// Resolve interfaces
|
|
815
835
|
if (ctx?.interfaces?.has(typeName)) {
|
|
836
|
+
// Check cache first
|
|
837
|
+
if (ctx.resolvedCache?.has(typeName)) {
|
|
838
|
+
return ctx.resolvedCache.get(typeName)!
|
|
839
|
+
}
|
|
816
840
|
const visited = ctx.visited ?? new Set<string>()
|
|
817
841
|
if (visited.has(typeName)) {
|
|
818
842
|
return { kind: 'any' } // Circular reference
|
|
@@ -851,7 +875,9 @@ function typeToInfo(
|
|
|
851
875
|
shape[propName] = typeToInfo(member.type, { ...ctx, visited })
|
|
852
876
|
}
|
|
853
877
|
}
|
|
854
|
-
|
|
878
|
+
const result = { kind: 'object' as const, shape }
|
|
879
|
+
ctx.resolvedCache?.set(typeName, result)
|
|
880
|
+
return result
|
|
855
881
|
}
|
|
856
882
|
|
|
857
883
|
// Check type parameter constraints/defaults from enclosing context
|
|
@@ -1476,14 +1502,14 @@ function transformFunctionToTJS(
|
|
|
1476
1502
|
const returnExample = node.type
|
|
1477
1503
|
? typeToExample(node.type, undefined, warnings, resolveCtx)
|
|
1478
1504
|
: ''
|
|
1479
|
-
// Use
|
|
1505
|
+
// Use :! to skip signature tests - TS types are compile-time only,
|
|
1480
1506
|
// the example values won't necessarily match runtime behavior
|
|
1481
1507
|
const returnAnnotation =
|
|
1482
1508
|
returnExample &&
|
|
1483
1509
|
returnExample !== 'undefined' &&
|
|
1484
1510
|
returnExample !== 'any' &&
|
|
1485
1511
|
!returnExample.startsWith('new ') // new Set(), new Map() etc. aren't valid TJS literals
|
|
1486
|
-
?
|
|
1512
|
+
? `:! ${returnExample}`
|
|
1487
1513
|
: ''
|
|
1488
1514
|
|
|
1489
1515
|
// Track degraded return type
|
|
@@ -1596,7 +1622,7 @@ function emitOverloadGroup(
|
|
|
1596
1622
|
: ''
|
|
1597
1623
|
const returnAnnotation =
|
|
1598
1624
|
returnExample && returnExample !== 'undefined' && returnExample !== 'any'
|
|
1599
|
-
?
|
|
1625
|
+
? `:! ${returnExample}`
|
|
1600
1626
|
: ''
|
|
1601
1627
|
|
|
1602
1628
|
const { line } = sourceFile.getLineAndCharacterOfPosition(
|
|
@@ -1723,12 +1749,12 @@ function transformClassToTJS(
|
|
|
1723
1749
|
const returnExample = member.type
|
|
1724
1750
|
? typeToExample(member.type, undefined, warnings, resolveCtx)
|
|
1725
1751
|
: ''
|
|
1726
|
-
// Use
|
|
1752
|
+
// Use :! to skip signature tests for TS-transpiled code
|
|
1727
1753
|
const returnAnnotation =
|
|
1728
1754
|
returnExample &&
|
|
1729
1755
|
returnExample !== 'undefined' &&
|
|
1730
1756
|
returnExample !== 'any'
|
|
1731
|
-
?
|
|
1757
|
+
? `:! ${returnExample}`
|
|
1732
1758
|
: ''
|
|
1733
1759
|
|
|
1734
1760
|
let body = '{ }'
|
|
@@ -1769,7 +1795,7 @@ function transformClassToTJS(
|
|
|
1769
1795
|
returnExample !== 'undefined' &&
|
|
1770
1796
|
returnExample !== 'any' &&
|
|
1771
1797
|
!returnExample.startsWith('new ')
|
|
1772
|
-
?
|
|
1798
|
+
? `: ${returnExample}`
|
|
1773
1799
|
: ''
|
|
1774
1800
|
|
|
1775
1801
|
let body = '{ }'
|
|
@@ -2406,6 +2432,7 @@ export function fromTS(
|
|
|
2406
2432
|
interfaces,
|
|
2407
2433
|
sourceFile,
|
|
2408
2434
|
warnings,
|
|
2435
|
+
resolvedCache: new Map(),
|
|
2409
2436
|
}
|
|
2410
2437
|
|
|
2411
2438
|
// Pre-scan: detect function overload groups
|