@tsonic/frontend 0.0.1

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 (145) hide show
  1. package/package.json +53 -0
  2. package/src/dependency-graph.ts +18 -0
  3. package/src/dotnet-metadata.ts +121 -0
  4. package/src/graph/builder.ts +81 -0
  5. package/src/graph/circular.ts +58 -0
  6. package/src/graph/extraction/exports.ts +55 -0
  7. package/src/graph/extraction/imports.ts +81 -0
  8. package/src/graph/extraction/index.ts +7 -0
  9. package/src/graph/extraction/orchestrator.ts +99 -0
  10. package/src/graph/extraction.ts +10 -0
  11. package/src/graph/helpers.ts +51 -0
  12. package/src/graph/index.ts +17 -0
  13. package/src/graph/types.ts +13 -0
  14. package/src/index.ts +80 -0
  15. package/src/ir/binding-resolution.test.ts +585 -0
  16. package/src/ir/builder/exports.ts +78 -0
  17. package/src/ir/builder/helpers.ts +27 -0
  18. package/src/ir/builder/imports.ts +153 -0
  19. package/src/ir/builder/index.ts +10 -0
  20. package/src/ir/builder/orchestrator.ts +178 -0
  21. package/src/ir/builder/statements.ts +55 -0
  22. package/src/ir/builder/types.ts +8 -0
  23. package/src/ir/builder/validation.ts +129 -0
  24. package/src/ir/builder.test.ts +581 -0
  25. package/src/ir/builder.ts +14 -0
  26. package/src/ir/converters/expressions/access.ts +99 -0
  27. package/src/ir/converters/expressions/calls.ts +137 -0
  28. package/src/ir/converters/expressions/collections.ts +84 -0
  29. package/src/ir/converters/expressions/functions.ts +62 -0
  30. package/src/ir/converters/expressions/helpers.ts +264 -0
  31. package/src/ir/converters/expressions/index.ts +43 -0
  32. package/src/ir/converters/expressions/literals.ts +22 -0
  33. package/src/ir/converters/expressions/operators.ts +147 -0
  34. package/src/ir/converters/expressions/other.ts +60 -0
  35. package/src/ir/converters/statements/control/blocks.ts +22 -0
  36. package/src/ir/converters/statements/control/conditionals.ts +67 -0
  37. package/src/ir/converters/statements/control/exceptions.ts +43 -0
  38. package/src/ir/converters/statements/control/index.ts +17 -0
  39. package/src/ir/converters/statements/control/loops.ts +99 -0
  40. package/src/ir/converters/statements/control.ts +17 -0
  41. package/src/ir/converters/statements/declarations/classes/constructors.ts +120 -0
  42. package/src/ir/converters/statements/declarations/classes/index.ts +12 -0
  43. package/src/ir/converters/statements/declarations/classes/methods.ts +61 -0
  44. package/src/ir/converters/statements/declarations/classes/orchestrator.ts +166 -0
  45. package/src/ir/converters/statements/declarations/classes/override-detection.ts +116 -0
  46. package/src/ir/converters/statements/declarations/classes/properties.ts +63 -0
  47. package/src/ir/converters/statements/declarations/classes.ts +6 -0
  48. package/src/ir/converters/statements/declarations/enums.ts +29 -0
  49. package/src/ir/converters/statements/declarations/functions.ts +39 -0
  50. package/src/ir/converters/statements/declarations/index.ts +14 -0
  51. package/src/ir/converters/statements/declarations/interfaces.ts +131 -0
  52. package/src/ir/converters/statements/declarations/registry.ts +45 -0
  53. package/src/ir/converters/statements/declarations/type-aliases.ts +25 -0
  54. package/src/ir/converters/statements/declarations/variables.ts +60 -0
  55. package/src/ir/converters/statements/declarations.ts +16 -0
  56. package/src/ir/converters/statements/helpers.ts +174 -0
  57. package/src/ir/converters/statements/index.ts +40 -0
  58. package/src/ir/expression-converter.ts +207 -0
  59. package/src/ir/generic-validator.ts +100 -0
  60. package/src/ir/hierarchical-bindings-e2e.test.ts +163 -0
  61. package/src/ir/index.ts +6 -0
  62. package/src/ir/statement-converter.ts +128 -0
  63. package/src/ir/type-converter/arrays.ts +20 -0
  64. package/src/ir/type-converter/converter.ts +10 -0
  65. package/src/ir/type-converter/functions.ts +22 -0
  66. package/src/ir/type-converter/index.ts +11 -0
  67. package/src/ir/type-converter/inference.ts +122 -0
  68. package/src/ir/type-converter/literals.ts +40 -0
  69. package/src/ir/type-converter/objects.ts +107 -0
  70. package/src/ir/type-converter/orchestrator.ts +85 -0
  71. package/src/ir/type-converter/patterns.ts +73 -0
  72. package/src/ir/type-converter/primitives.ts +57 -0
  73. package/src/ir/type-converter/references.ts +64 -0
  74. package/src/ir/type-converter/unions-intersections.ts +34 -0
  75. package/src/ir/type-converter.ts +13 -0
  76. package/src/ir/types/expressions.ts +215 -0
  77. package/src/ir/types/guards.ts +39 -0
  78. package/src/ir/types/helpers.ts +135 -0
  79. package/src/ir/types/index.ts +108 -0
  80. package/src/ir/types/ir-types.ts +96 -0
  81. package/src/ir/types/module.ts +57 -0
  82. package/src/ir/types/statements.ts +238 -0
  83. package/src/ir/types.ts +97 -0
  84. package/src/metadata/bindings-loader.test.ts +144 -0
  85. package/src/metadata/bindings-loader.ts +357 -0
  86. package/src/metadata/index.ts +15 -0
  87. package/src/metadata/library-loader.ts +153 -0
  88. package/src/metadata/loader.test.ts +156 -0
  89. package/src/metadata/loader.ts +382 -0
  90. package/src/program/bindings.test.ts +512 -0
  91. package/src/program/bindings.ts +253 -0
  92. package/src/program/config.ts +30 -0
  93. package/src/program/creation.ts +249 -0
  94. package/src/program/dependency-graph.ts +245 -0
  95. package/src/program/diagnostics.ts +103 -0
  96. package/src/program/index.ts +19 -0
  97. package/src/program/metadata.ts +68 -0
  98. package/src/program/queries.ts +18 -0
  99. package/src/program/types.ts +38 -0
  100. package/src/program.ts +13 -0
  101. package/src/resolver/dotnet-import-resolver.ts +226 -0
  102. package/src/resolver/import-resolution.ts +177 -0
  103. package/src/resolver/index.ts +18 -0
  104. package/src/resolver/namespace.test.ts +86 -0
  105. package/src/resolver/namespace.ts +42 -0
  106. package/src/resolver/naming.ts +38 -0
  107. package/src/resolver/path-resolution.ts +22 -0
  108. package/src/resolver/types.ts +15 -0
  109. package/src/resolver.test.ts +155 -0
  110. package/src/resolver.ts +14 -0
  111. package/src/symbol-table/builder.ts +114 -0
  112. package/src/symbol-table/creation.ts +42 -0
  113. package/src/symbol-table/helpers.ts +18 -0
  114. package/src/symbol-table/index.ts +13 -0
  115. package/src/symbol-table/queries.ts +42 -0
  116. package/src/symbol-table/types.ts +28 -0
  117. package/src/symbol-table.ts +14 -0
  118. package/src/types/bindings.ts +172 -0
  119. package/src/types/diagnostic.test.ts +164 -0
  120. package/src/types/diagnostic.ts +153 -0
  121. package/src/types/explicit-views.test.ts +113 -0
  122. package/src/types/explicit-views.ts +218 -0
  123. package/src/types/metadata.ts +229 -0
  124. package/src/types/module.ts +99 -0
  125. package/src/types/nested-types.test.ts +194 -0
  126. package/src/types/nested-types.ts +215 -0
  127. package/src/types/parameter-modifiers.ts +173 -0
  128. package/src/types/ref-parameters.test.ts +192 -0
  129. package/src/types/ref-parameters.ts +268 -0
  130. package/src/types/result.test.ts +157 -0
  131. package/src/types/result.ts +48 -0
  132. package/src/types/support-types.test.ts +81 -0
  133. package/src/types/support-types.ts +288 -0
  134. package/src/types/test-harness.ts +180 -0
  135. package/src/validation/exports.ts +98 -0
  136. package/src/validation/features.ts +89 -0
  137. package/src/validation/generics.ts +40 -0
  138. package/src/validation/helpers.ts +31 -0
  139. package/src/validation/imports.ts +97 -0
  140. package/src/validation/index.ts +11 -0
  141. package/src/validation/orchestrator.ts +51 -0
  142. package/src/validation/static-safety.ts +267 -0
  143. package/src/validator.test.ts +468 -0
  144. package/src/validator.ts +15 -0
  145. package/tsconfig.json +13 -0
@@ -0,0 +1,163 @@
1
+ /**
2
+ * End-to-end test for hierarchical bindings
3
+ * Verifies the full pipeline: TypeScript -> IR -> C# with hierarchical bindings
4
+ */
5
+
6
+ import { describe, it } from "mocha";
7
+ import { expect } from "chai";
8
+ import * as ts from "typescript";
9
+ import { buildIrModule } from "./builder.js";
10
+ import { DotnetMetadataRegistry } from "../dotnet-metadata.js";
11
+ import { BindingRegistry } from "../program/bindings.js";
12
+ import { createDotNetImportResolver } from "../resolver/dotnet-import-resolver.js";
13
+
14
+ describe("Hierarchical Bindings End-to-End", () => {
15
+ it("should resolve hierarchical bindings in IR for member access chain", () => {
16
+ // TypeScript source with systemLinq.enumerable.selectMany
17
+ const source = `
18
+ export function processData() {
19
+ const arr = [1, 2, 3];
20
+ // systemLinq.enumerable.selectMany should resolve to System.Linq.Enumerable.SelectMany
21
+ const result = systemLinq.enumerable.selectMany(arr, x => [x, x * 2]);
22
+ return result;
23
+ }
24
+ `;
25
+
26
+ // Create hierarchical binding manifest
27
+ const bindings = new BindingRegistry();
28
+ bindings.addBindings("/test/system-linq.json", {
29
+ assembly: "System.Linq",
30
+ namespaces: [
31
+ {
32
+ name: "System.Linq",
33
+ alias: "systemLinq",
34
+ types: [
35
+ {
36
+ name: "Enumerable",
37
+ alias: "enumerable",
38
+ kind: "class",
39
+ members: [
40
+ {
41
+ kind: "method",
42
+ name: "SelectMany",
43
+ alias: "selectMany",
44
+ binding: {
45
+ assembly: "System.Linq",
46
+ type: "System.Linq.Enumerable",
47
+ member: "SelectMany",
48
+ },
49
+ },
50
+ ],
51
+ },
52
+ ],
53
+ },
54
+ ],
55
+ });
56
+
57
+ // Create TypeScript program
58
+ const fileName = "/test/sample.ts";
59
+ const sourceFile = ts.createSourceFile(
60
+ fileName,
61
+ source,
62
+ ts.ScriptTarget.ES2022,
63
+ true,
64
+ ts.ScriptKind.TS
65
+ );
66
+
67
+ const program = ts.createProgram(
68
+ [fileName],
69
+ {
70
+ target: ts.ScriptTarget.ES2022,
71
+ module: ts.ModuleKind.ES2022,
72
+ },
73
+ {
74
+ getSourceFile: (name) => (name === fileName ? sourceFile : undefined),
75
+ writeFile: () => {},
76
+ getCurrentDirectory: () => "/test",
77
+ getDirectories: () => [],
78
+ fileExists: () => true,
79
+ readFile: () => source,
80
+ getCanonicalFileName: (f) => f,
81
+ useCaseSensitiveFileNames: () => true,
82
+ getNewLine: () => "\n",
83
+ getDefaultLibFileName: (_options) => "lib.d.ts",
84
+ }
85
+ );
86
+
87
+ const testProgram = {
88
+ program,
89
+ checker: program.getTypeChecker(),
90
+ options: { sourceRoot: "/test", rootNamespace: "TestApp", strict: true },
91
+ sourceFiles: [sourceFile],
92
+ metadata: new DotnetMetadataRegistry(),
93
+ bindings,
94
+ dotnetResolver: createDotNetImportResolver("/test"),
95
+ };
96
+
97
+ // Build IR
98
+ const irResult = buildIrModule(sourceFile, testProgram, {
99
+ sourceRoot: "/test",
100
+ rootNamespace: "TestApp",
101
+ });
102
+
103
+ // MUST succeed - this is a strict test
104
+ if (!irResult.ok) {
105
+ console.error("IR build failed:", irResult.error);
106
+ throw new Error(
107
+ `IR build MUST succeed for e2e test, got error: ${JSON.stringify(irResult.error)}`
108
+ );
109
+ }
110
+
111
+ const irModule = irResult.value;
112
+
113
+ // Navigate to the selectMany call in IR
114
+ const funcDecl = irModule.body[0];
115
+ expect(funcDecl?.kind).to.equal(
116
+ "functionDeclaration",
117
+ "First body item should be function declaration"
118
+ );
119
+ if (funcDecl?.kind !== "functionDeclaration") return;
120
+
121
+ // First statement: const arr = [1, 2, 3];
122
+ // Second statement: const result = systemLinq.enumerable.selectMany(...)
123
+ const resultDecl = funcDecl.body.statements[1];
124
+ expect(resultDecl?.kind).to.equal(
125
+ "variableDeclaration",
126
+ "Second statement should be variable declaration for result"
127
+ );
128
+ if (resultDecl?.kind !== "variableDeclaration") return;
129
+
130
+ const declarator = resultDecl.declarations[0];
131
+ if (!declarator?.initializer) {
132
+ throw new Error("Expected initializer for result variable");
133
+ }
134
+
135
+ // The initializer is the systemLinq.enumerable.selectMany(...) call
136
+ const callExpr = declarator.initializer;
137
+ expect(callExpr.kind).to.equal(
138
+ "call",
139
+ "Initializer should be call expression"
140
+ );
141
+ if (callExpr.kind !== "call") return;
142
+
143
+ // The callee is systemLinq.enumerable.selectMany (member access)
144
+ const memberExpr = callExpr.callee;
145
+ expect(memberExpr.kind).to.equal(
146
+ "memberAccess",
147
+ "Callee should be member access"
148
+ );
149
+ if (memberExpr.kind !== "memberAccess") return;
150
+
151
+ // CRITICAL: Verify memberBinding was resolved by the hierarchical binding system
152
+ expect(
153
+ memberExpr.memberBinding,
154
+ "Member binding MUST be resolved for systemLinq.enumerable.selectMany"
155
+ ).to.not.equal(undefined);
156
+
157
+ expect(memberExpr.memberBinding?.assembly).to.equal("System.Linq");
158
+ expect(memberExpr.memberBinding?.type).to.equal("System.Linq.Enumerable");
159
+ expect(memberExpr.memberBinding?.member).to.equal("SelectMany");
160
+
161
+ console.log("✅ End-to-end test passed: Hierarchical bindings work!");
162
+ });
163
+ });
@@ -0,0 +1,6 @@
1
+ /**
2
+ * IR module exports
3
+ */
4
+
5
+ export * from "./types.js";
6
+ export { buildIr, buildIrModule, type IrBuildOptions } from "./builder.js";
@@ -0,0 +1,128 @@
1
+ /**
2
+ * Statement converter - TypeScript AST to IR statements
3
+ * Main dispatcher - delegates to specialized modules
4
+ */
5
+
6
+ import * as ts from "typescript";
7
+ import { IrStatement } from "./types.js";
8
+ import { convertExpression } from "./expression-converter.js";
9
+
10
+ // Import converters from specialized modules
11
+ import {
12
+ convertVariableStatement,
13
+ convertFunctionDeclaration,
14
+ convertClassDeclaration,
15
+ convertInterfaceDeclaration,
16
+ convertEnumDeclaration,
17
+ convertTypeAliasDeclaration,
18
+ } from "./converters/statements/declarations.js";
19
+
20
+ import {
21
+ convertIfStatement,
22
+ convertWhileStatement,
23
+ convertForStatement,
24
+ convertForOfStatement,
25
+ convertForInStatement,
26
+ convertSwitchStatement,
27
+ convertTryStatement,
28
+ convertBlockStatement,
29
+ } from "./converters/statements/control.js";
30
+
31
+ /**
32
+ * Main statement converter dispatcher
33
+ */
34
+ export const convertStatement = (
35
+ node: ts.Node,
36
+ checker: ts.TypeChecker
37
+ ): IrStatement | null => {
38
+ if (ts.isVariableStatement(node)) {
39
+ return convertVariableStatement(node, checker);
40
+ }
41
+ if (ts.isFunctionDeclaration(node)) {
42
+ return convertFunctionDeclaration(node, checker);
43
+ }
44
+ if (ts.isClassDeclaration(node)) {
45
+ return convertClassDeclaration(node, checker);
46
+ }
47
+ if (ts.isInterfaceDeclaration(node)) {
48
+ return convertInterfaceDeclaration(node, checker);
49
+ }
50
+ if (ts.isEnumDeclaration(node)) {
51
+ return convertEnumDeclaration(node, checker);
52
+ }
53
+ if (ts.isTypeAliasDeclaration(node)) {
54
+ return convertTypeAliasDeclaration(node, checker);
55
+ }
56
+ if (ts.isExpressionStatement(node)) {
57
+ return {
58
+ kind: "expressionStatement",
59
+ expression: convertExpression(node.expression, checker),
60
+ };
61
+ }
62
+ if (ts.isReturnStatement(node)) {
63
+ return {
64
+ kind: "returnStatement",
65
+ expression: node.expression
66
+ ? convertExpression(node.expression, checker)
67
+ : undefined,
68
+ };
69
+ }
70
+ if (ts.isIfStatement(node)) {
71
+ return convertIfStatement(node, checker);
72
+ }
73
+ if (ts.isWhileStatement(node)) {
74
+ return convertWhileStatement(node, checker);
75
+ }
76
+ if (ts.isForStatement(node)) {
77
+ return convertForStatement(node, checker);
78
+ }
79
+ if (ts.isForOfStatement(node)) {
80
+ return convertForOfStatement(node, checker);
81
+ }
82
+ if (ts.isForInStatement(node)) {
83
+ return convertForInStatement(node, checker);
84
+ }
85
+ if (ts.isSwitchStatement(node)) {
86
+ return convertSwitchStatement(node, checker);
87
+ }
88
+ if (ts.isThrowStatement(node)) {
89
+ if (!node.expression) {
90
+ return null;
91
+ }
92
+ return {
93
+ kind: "throwStatement",
94
+ expression: convertExpression(node.expression, checker),
95
+ };
96
+ }
97
+ if (ts.isTryStatement(node)) {
98
+ return convertTryStatement(node, checker);
99
+ }
100
+ if (ts.isBlock(node)) {
101
+ return convertBlockStatement(node, checker);
102
+ }
103
+ if (ts.isBreakStatement(node)) {
104
+ return {
105
+ kind: "breakStatement",
106
+ label: node.label?.text,
107
+ };
108
+ }
109
+ if (ts.isContinueStatement(node)) {
110
+ return {
111
+ kind: "continueStatement",
112
+ label: node.label?.text,
113
+ };
114
+ }
115
+ if (ts.isEmptyStatement(node)) {
116
+ return { kind: "emptyStatement" };
117
+ }
118
+
119
+ return null;
120
+ };
121
+
122
+ // Re-export commonly used functions for backward compatibility
123
+ export { convertBlockStatement } from "./converters/statements/control.js";
124
+ export { convertParameters } from "./converters/statements/helpers.js";
125
+ export {
126
+ setMetadataRegistry,
127
+ setBindingRegistry,
128
+ } from "./converters/statements/declarations.js";
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Array type conversion
3
+ */
4
+
5
+ import * as ts from "typescript";
6
+ import { IrType } from "../types.js";
7
+
8
+ /**
9
+ * Convert TypeScript array type to IR array type
10
+ */
11
+ export const convertArrayType = (
12
+ node: ts.ArrayTypeNode,
13
+ checker: ts.TypeChecker,
14
+ convertType: (node: ts.TypeNode, checker: ts.TypeChecker) => IrType
15
+ ): IrType => {
16
+ return {
17
+ kind: "arrayType",
18
+ elementType: convertType(node.elementType, checker),
19
+ };
20
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Type converter - TypeScript types to IR types
3
+ * Main dispatcher - re-exports from orchestrator
4
+ */
5
+
6
+ export {
7
+ convertType,
8
+ convertFunctionType,
9
+ convertObjectType,
10
+ } from "./orchestrator.js";
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Function type conversion
3
+ */
4
+
5
+ import * as ts from "typescript";
6
+ import { IrType, IrFunctionType } from "../types.js";
7
+ import { convertParameters as convertParametersFromStatement } from "../statement-converter.js";
8
+
9
+ /**
10
+ * Convert TypeScript function type to IR function type
11
+ */
12
+ export const convertFunctionType = (
13
+ node: ts.FunctionTypeNode,
14
+ checker: ts.TypeChecker,
15
+ convertType: (node: ts.TypeNode, checker: ts.TypeChecker) => IrType
16
+ ): IrFunctionType => {
17
+ return {
18
+ kind: "functionType",
19
+ parameters: convertParametersFromStatement(node.parameters, checker),
20
+ returnType: convertType(node.type, checker),
21
+ };
22
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Type converter - Public API
3
+ */
4
+
5
+ export {
6
+ convertType,
7
+ convertFunctionType,
8
+ convertObjectType,
9
+ } from "./converter.js";
10
+ export { convertBindingName } from "./patterns.js";
11
+ export { inferType, convertTsTypeToIr } from "./inference.js";
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Type inference - Converts TypeScript inferred types to IR types
3
+ *
4
+ * This uses the TypeChecker to get the inferred type and converts it to IR.
5
+ * Used for declarations without explicit type annotations where the type
6
+ * must be inferred from the initializer.
7
+ */
8
+
9
+ import * as ts from "typescript";
10
+ import type { IrType } from "../types.js";
11
+
12
+ /**
13
+ * Infer IR type from a declaration node using the TypeChecker.
14
+ * Returns undefined for complex types that cannot be easily represented.
15
+ */
16
+ export const inferType = (
17
+ node: ts.VariableDeclaration | ts.PropertyDeclaration,
18
+ checker: ts.TypeChecker
19
+ ): IrType | undefined => {
20
+ const type = checker.getTypeAtLocation(node);
21
+ return convertTsTypeToIr(type, checker);
22
+ };
23
+
24
+ /**
25
+ * Convert a TypeScript Type (from checker) to IR type.
26
+ * This is different from convertType which takes a TypeNode (syntax).
27
+ */
28
+ export const convertTsTypeToIr = (
29
+ type: ts.Type,
30
+ checker: ts.TypeChecker
31
+ ): IrType | undefined => {
32
+ const flags = type.flags;
33
+
34
+ // Primitives
35
+ if (flags & ts.TypeFlags.Number || flags & ts.TypeFlags.NumberLiteral) {
36
+ return { kind: "primitiveType", name: "number" };
37
+ }
38
+ if (flags & ts.TypeFlags.String || flags & ts.TypeFlags.StringLiteral) {
39
+ return { kind: "primitiveType", name: "string" };
40
+ }
41
+ if (flags & ts.TypeFlags.Boolean || flags & ts.TypeFlags.BooleanLiteral) {
42
+ return { kind: "primitiveType", name: "boolean" };
43
+ }
44
+ if (flags & ts.TypeFlags.Void) {
45
+ return { kind: "voidType" };
46
+ }
47
+ if (flags & ts.TypeFlags.Null) {
48
+ return { kind: "primitiveType", name: "null" };
49
+ }
50
+ if (flags & ts.TypeFlags.Undefined) {
51
+ return { kind: "primitiveType", name: "undefined" };
52
+ }
53
+
54
+ // Object type - check if it's an array
55
+ if (flags & ts.TypeFlags.Object) {
56
+ // Check for array type
57
+ if (checker.isArrayType(type)) {
58
+ const typeArgs = checker.getTypeArguments(type as ts.TypeReference);
59
+ if (typeArgs.length > 0) {
60
+ const elementType = convertTsTypeToIr(typeArgs[0]!, checker);
61
+ if (elementType) {
62
+ return { kind: "arrayType", elementType };
63
+ }
64
+ }
65
+ return { kind: "arrayType", elementType: { kind: "anyType" } };
66
+ }
67
+
68
+ // Check for callable signatures (function types)
69
+ const callSignatures = type.getCallSignatures();
70
+ if (callSignatures.length > 0) {
71
+ // Function types need complex handling - return undefined for now
72
+ return undefined;
73
+ }
74
+
75
+ // Check for symbol with name (class, interface, etc.)
76
+ const objectType = type as ts.ObjectType;
77
+ if (objectType.symbol) {
78
+ const name = objectType.symbol.name;
79
+ // Skip internal TypeScript symbol names
80
+ if (name.startsWith("__")) {
81
+ return undefined;
82
+ }
83
+ // For named types, return as reference type with type arguments if generic
84
+ if (name && name !== "Object" && name !== "Array") {
85
+ // Extract type arguments for generic types
86
+ const typeRef = type as ts.TypeReference;
87
+ const typeArgs = checker.getTypeArguments(typeRef);
88
+ if (typeArgs && typeArgs.length > 0) {
89
+ const irTypeArgs = typeArgs
90
+ .map((arg) => convertTsTypeToIr(arg, checker))
91
+ .filter((t): t is IrType => t !== undefined);
92
+ if (irTypeArgs.length === typeArgs.length) {
93
+ return { kind: "referenceType", name, typeArguments: irTypeArgs };
94
+ }
95
+ }
96
+ return { kind: "referenceType", name };
97
+ }
98
+ }
99
+
100
+ // Anonymous object type
101
+ return undefined;
102
+ }
103
+
104
+ // Type parameters (e.g., T in Container<T>)
105
+ if (flags & ts.TypeFlags.TypeParameter) {
106
+ const typeParam = type as ts.TypeParameter;
107
+ const name = typeParam.symbol?.name ?? "T";
108
+ return { kind: "referenceType", name };
109
+ }
110
+
111
+ // Any and unknown
112
+ if (flags & ts.TypeFlags.Any || flags & ts.TypeFlags.Unknown) {
113
+ return { kind: "anyType" };
114
+ }
115
+
116
+ // Union and intersection types - too complex for simple inference
117
+ if (flags & ts.TypeFlags.Union || flags & ts.TypeFlags.Intersection) {
118
+ return undefined;
119
+ }
120
+
121
+ return undefined;
122
+ };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Literal type conversion
3
+ */
4
+
5
+ import * as ts from "typescript";
6
+ import { IrType } from "../types.js";
7
+
8
+ /**
9
+ * Convert TypeScript literal type to IR literal type
10
+ */
11
+ export const convertLiteralType = (node: ts.LiteralTypeNode): IrType => {
12
+ const literal = node.literal;
13
+
14
+ if (ts.isStringLiteral(literal)) {
15
+ return { kind: "literalType", value: literal.text };
16
+ }
17
+
18
+ if (ts.isNumericLiteral(literal)) {
19
+ return { kind: "literalType", value: Number(literal.text) };
20
+ }
21
+
22
+ if (literal.kind === ts.SyntaxKind.TrueKeyword) {
23
+ return { kind: "literalType", value: true };
24
+ }
25
+
26
+ if (literal.kind === ts.SyntaxKind.FalseKeyword) {
27
+ return { kind: "literalType", value: false };
28
+ }
29
+
30
+ if (literal.kind === ts.SyntaxKind.NullKeyword) {
31
+ return { kind: "primitiveType", name: "null" };
32
+ }
33
+
34
+ if (literal.kind === ts.SyntaxKind.UndefinedKeyword) {
35
+ return { kind: "primitiveType", name: "undefined" };
36
+ }
37
+
38
+ // Fallback
39
+ return { kind: "anyType" };
40
+ };
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Object/interface type conversion
3
+ */
4
+
5
+ import * as ts from "typescript";
6
+ import {
7
+ IrType,
8
+ IrObjectType,
9
+ IrDictionaryType,
10
+ IrInterfaceMember,
11
+ IrPropertySignature,
12
+ IrMethodSignature,
13
+ } from "../types.js";
14
+ import { convertParameters as convertParametersFromStatement } from "../statement-converter.js";
15
+
16
+ /**
17
+ * Convert TypeScript object literal type to IR type.
18
+ *
19
+ * Returns IrDictionaryType for pure index signature types like:
20
+ * - `{ [k: string]: T }`
21
+ * - `{ [k: number]: T }`
22
+ *
23
+ * Returns IrObjectType for regular object types with named members.
24
+ */
25
+ export const convertObjectType = (
26
+ node: ts.TypeLiteralNode,
27
+ checker: ts.TypeChecker,
28
+ convertType: (node: ts.TypeNode, checker: ts.TypeChecker) => IrType
29
+ ): IrObjectType | IrDictionaryType => {
30
+ // Check for pure index signature type (no other members)
31
+ const indexSignatures = node.members.filter(ts.isIndexSignatureDeclaration);
32
+ const otherMembers = node.members.filter(
33
+ (m) => !ts.isIndexSignatureDeclaration(m)
34
+ );
35
+
36
+ // If ONLY index signature(s) exist, convert to dictionary type
37
+ if (indexSignatures.length > 0 && otherMembers.length === 0) {
38
+ // Use the first index signature (TypeScript allows multiple, but we take first)
39
+ const indexSig = indexSignatures[0]!;
40
+ const keyParam = indexSig.parameters[0];
41
+
42
+ // Determine key type from parameter type
43
+ const keyType: IrType = keyParam?.type
44
+ ? convertKeyType(keyParam.type)
45
+ : { kind: "primitiveType", name: "string" };
46
+
47
+ // Determine value type
48
+ const valueType: IrType = indexSig.type
49
+ ? convertType(indexSig.type, checker)
50
+ : { kind: "anyType" };
51
+
52
+ return {
53
+ kind: "dictionaryType",
54
+ keyType,
55
+ valueType,
56
+ };
57
+ }
58
+
59
+ // Regular object type with named members
60
+ const members: IrInterfaceMember[] = [];
61
+
62
+ node.members.forEach((member) => {
63
+ if (ts.isPropertySignature(member) && member.type) {
64
+ const propSig: IrPropertySignature = {
65
+ kind: "propertySignature",
66
+ name:
67
+ member.name && ts.isIdentifier(member.name)
68
+ ? member.name.text
69
+ : "[computed]",
70
+ type: convertType(member.type, checker),
71
+ isOptional: !!member.questionToken,
72
+ isReadonly: !!member.modifiers?.some(
73
+ (m) => m.kind === ts.SyntaxKind.ReadonlyKeyword
74
+ ),
75
+ };
76
+ members.push(propSig);
77
+ } else if (ts.isMethodSignature(member)) {
78
+ const methSig: IrMethodSignature = {
79
+ kind: "methodSignature",
80
+ name:
81
+ member.name && ts.isIdentifier(member.name)
82
+ ? member.name.text
83
+ : "[computed]",
84
+ parameters: convertParametersFromStatement(member.parameters, checker),
85
+ returnType: member.type ? convertType(member.type, checker) : undefined,
86
+ };
87
+ members.push(methSig);
88
+ }
89
+ });
90
+
91
+ return { kind: "objectType", members };
92
+ };
93
+
94
+ /**
95
+ * Convert index signature key type to IR type.
96
+ * Only string and number are valid as index signature keys.
97
+ */
98
+ const convertKeyType = (typeNode: ts.TypeNode): IrType => {
99
+ if (typeNode.kind === ts.SyntaxKind.StringKeyword) {
100
+ return { kind: "primitiveType", name: "string" };
101
+ }
102
+ if (typeNode.kind === ts.SyntaxKind.NumberKeyword) {
103
+ return { kind: "primitiveType", name: "number" };
104
+ }
105
+ // Fallback to string for other cases
106
+ return { kind: "primitiveType", name: "string" };
107
+ };