@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,137 @@
1
+ /**
2
+ * Call and new expression converters
3
+ */
4
+
5
+ import * as ts from "typescript";
6
+ import { IrCallExpression, IrNewExpression } from "../../types.js";
7
+ import {
8
+ getInferredType,
9
+ extractTypeArguments,
10
+ checkIfRequiresSpecialization,
11
+ } from "./helpers.js";
12
+ import { convertExpression } from "../../expression-converter.js";
13
+
14
+ /**
15
+ * Extract argument passing modes from resolved signature
16
+ * Returns array aligned with arguments, indicating ref/out/in/value for each
17
+ */
18
+ const extractArgumentPassing = (
19
+ node: ts.CallExpression | ts.NewExpression,
20
+ checker: ts.TypeChecker
21
+ ): readonly ("value" | "ref" | "out" | "in")[] | undefined => {
22
+ try {
23
+ const signature = checker.getResolvedSignature(node);
24
+ if (!signature || !signature.declaration) {
25
+ return undefined;
26
+ }
27
+
28
+ const decl = signature.declaration;
29
+ let parameters: readonly ts.ParameterDeclaration[] = [];
30
+
31
+ // Extract parameters from declaration
32
+ if (
33
+ ts.isFunctionDeclaration(decl) ||
34
+ ts.isMethodDeclaration(decl) ||
35
+ ts.isConstructorDeclaration(decl) ||
36
+ ts.isArrowFunction(decl) ||
37
+ ts.isFunctionExpression(decl)
38
+ ) {
39
+ parameters = decl.parameters;
40
+ }
41
+
42
+ if (parameters.length === 0) {
43
+ return undefined;
44
+ }
45
+
46
+ // Build passing mode for each parameter
47
+ const passingModes: ("value" | "ref" | "out" | "in")[] = [];
48
+
49
+ for (const param of parameters) {
50
+ let passing: "value" | "ref" | "out" | "in" = "value";
51
+
52
+ // Check if parameter type is ref<T>, out<T>, or in<T>
53
+ if (
54
+ param.type &&
55
+ ts.isTypeReferenceNode(param.type) &&
56
+ ts.isIdentifier(param.type.typeName)
57
+ ) {
58
+ const typeName = param.type.typeName.text;
59
+ if (
60
+ (typeName === "ref" || typeName === "out" || typeName === "in") &&
61
+ param.type.typeArguments &&
62
+ param.type.typeArguments.length > 0
63
+ ) {
64
+ passing = typeName === "in" ? "in" : typeName;
65
+ }
66
+ }
67
+
68
+ passingModes.push(passing);
69
+ }
70
+
71
+ return passingModes;
72
+ } catch {
73
+ return undefined;
74
+ }
75
+ };
76
+
77
+ /**
78
+ * Convert call expression
79
+ */
80
+ export const convertCallExpression = (
81
+ node: ts.CallExpression,
82
+ checker: ts.TypeChecker
83
+ ): IrCallExpression => {
84
+ // Extract type arguments from the call signature
85
+ const typeArguments = extractTypeArguments(node, checker);
86
+ const requiresSpecialization = checkIfRequiresSpecialization(node, checker);
87
+ const argumentPassing = extractArgumentPassing(node, checker);
88
+
89
+ return {
90
+ kind: "call",
91
+ callee: convertExpression(node.expression, checker),
92
+ arguments: node.arguments.map((arg) => {
93
+ if (ts.isSpreadElement(arg)) {
94
+ return {
95
+ kind: "spread" as const,
96
+ expression: convertExpression(arg.expression, checker),
97
+ };
98
+ }
99
+ return convertExpression(arg, checker);
100
+ }),
101
+ isOptional: node.questionDotToken !== undefined,
102
+ inferredType: getInferredType(node, checker),
103
+ typeArguments,
104
+ requiresSpecialization,
105
+ argumentPassing,
106
+ };
107
+ };
108
+
109
+ /**
110
+ * Convert new expression
111
+ */
112
+ export const convertNewExpression = (
113
+ node: ts.NewExpression,
114
+ checker: ts.TypeChecker
115
+ ): IrNewExpression => {
116
+ // Extract type arguments from the constructor signature
117
+ const typeArguments = extractTypeArguments(node, checker);
118
+ const requiresSpecialization = checkIfRequiresSpecialization(node, checker);
119
+
120
+ return {
121
+ kind: "new",
122
+ callee: convertExpression(node.expression, checker),
123
+ arguments:
124
+ node.arguments?.map((arg) => {
125
+ if (ts.isSpreadElement(arg)) {
126
+ return {
127
+ kind: "spread" as const,
128
+ expression: convertExpression(arg.expression, checker),
129
+ };
130
+ }
131
+ return convertExpression(arg, checker);
132
+ }) ?? [],
133
+ inferredType: getInferredType(node, checker),
134
+ typeArguments,
135
+ requiresSpecialization,
136
+ };
137
+ };
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Collection expression converters (arrays and objects)
3
+ */
4
+
5
+ import * as ts from "typescript";
6
+ import {
7
+ IrArrayExpression,
8
+ IrObjectExpression,
9
+ IrObjectProperty,
10
+ } from "../../types.js";
11
+ import { getInferredType, getContextualType } from "./helpers.js";
12
+ import { convertExpression } from "../../expression-converter.js";
13
+
14
+ /**
15
+ * Convert array literal expression
16
+ */
17
+ export const convertArrayLiteral = (
18
+ node: ts.ArrayLiteralExpression,
19
+ checker: ts.TypeChecker
20
+ ): IrArrayExpression => {
21
+ return {
22
+ kind: "array",
23
+ elements: node.elements.map((elem) => {
24
+ if (ts.isOmittedExpression(elem)) {
25
+ return undefined; // Hole in sparse array
26
+ }
27
+ if (ts.isSpreadElement(elem)) {
28
+ return {
29
+ kind: "spread" as const,
30
+ expression: convertExpression(elem.expression, checker),
31
+ };
32
+ }
33
+ return convertExpression(elem, checker);
34
+ }),
35
+ inferredType: getInferredType(node, checker),
36
+ };
37
+ };
38
+
39
+ /**
40
+ * Convert object literal expression
41
+ */
42
+ export const convertObjectLiteral = (
43
+ node: ts.ObjectLiteralExpression,
44
+ checker: ts.TypeChecker
45
+ ): IrObjectExpression => {
46
+ const properties: IrObjectProperty[] = [];
47
+
48
+ node.properties.forEach((prop) => {
49
+ if (ts.isPropertyAssignment(prop)) {
50
+ const key = ts.isComputedPropertyName(prop.name)
51
+ ? convertExpression(prop.name.expression, checker)
52
+ : ts.isIdentifier(prop.name)
53
+ ? prop.name.text
54
+ : String(prop.name.text);
55
+
56
+ properties.push({
57
+ kind: "property",
58
+ key,
59
+ value: convertExpression(prop.initializer, checker),
60
+ shorthand: false,
61
+ });
62
+ } else if (ts.isShorthandPropertyAssignment(prop)) {
63
+ properties.push({
64
+ kind: "property",
65
+ key: prop.name.text,
66
+ value: { kind: "identifier", name: prop.name.text },
67
+ shorthand: true,
68
+ });
69
+ } else if (ts.isSpreadAssignment(prop)) {
70
+ properties.push({
71
+ kind: "spread",
72
+ expression: convertExpression(prop.expression, checker),
73
+ });
74
+ }
75
+ // Skip getters/setters/methods for now (can add later if needed)
76
+ });
77
+
78
+ return {
79
+ kind: "object",
80
+ properties,
81
+ inferredType: getInferredType(node, checker),
82
+ contextualType: getContextualType(node, checker),
83
+ };
84
+ };
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Function expression converters (function expressions and arrow functions)
3
+ */
4
+
5
+ import * as ts from "typescript";
6
+ import {
7
+ IrFunctionExpression,
8
+ IrArrowFunctionExpression,
9
+ } from "../../types.js";
10
+ import { getInferredType } from "./helpers.js";
11
+ import { convertExpression } from "../../expression-converter.js";
12
+ import {
13
+ convertParameters,
14
+ convertBlockStatement,
15
+ } from "../../statement-converter.js";
16
+ import { convertType } from "../../type-converter.js";
17
+
18
+ /**
19
+ * Convert function expression
20
+ */
21
+ export const convertFunctionExpression = (
22
+ node: ts.FunctionExpression,
23
+ checker: ts.TypeChecker
24
+ ): IrFunctionExpression => {
25
+ return {
26
+ kind: "functionExpression",
27
+ name: node.name?.text,
28
+ parameters: convertParameters(node.parameters, checker),
29
+ returnType: node.type ? convertType(node.type, checker) : undefined,
30
+ body: node.body
31
+ ? convertBlockStatement(node.body, checker)
32
+ : { kind: "blockStatement", statements: [] },
33
+ isAsync: !!node.modifiers?.some(
34
+ (m) => m.kind === ts.SyntaxKind.AsyncKeyword
35
+ ),
36
+ isGenerator: !!node.asteriskToken,
37
+ inferredType: getInferredType(node, checker),
38
+ };
39
+ };
40
+
41
+ /**
42
+ * Convert arrow function expression
43
+ */
44
+ export const convertArrowFunction = (
45
+ node: ts.ArrowFunction,
46
+ checker: ts.TypeChecker
47
+ ): IrArrowFunctionExpression => {
48
+ const body = ts.isBlock(node.body)
49
+ ? convertBlockStatement(node.body, checker)
50
+ : convertExpression(node.body, checker);
51
+
52
+ return {
53
+ kind: "arrowFunction",
54
+ parameters: convertParameters(node.parameters, checker),
55
+ returnType: node.type ? convertType(node.type, checker) : undefined,
56
+ body,
57
+ isAsync: !!node.modifiers?.some(
58
+ (m) => m.kind === ts.SyntaxKind.AsyncKeyword
59
+ ),
60
+ inferredType: getInferredType(node, checker),
61
+ };
62
+ };
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Helper functions for expression conversion
3
+ */
4
+
5
+ import * as ts from "typescript";
6
+ import { IrType } from "../../types.js";
7
+ import { convertType, convertTsTypeToIr } from "../../type-converter.js";
8
+
9
+ /**
10
+ * Helper to get inferred type from TypeScript node
11
+ * Prefers contextual type (from assignment target, return position, etc.)
12
+ * over literal type to handle cases like empty arrays `[]` correctly.
13
+ */
14
+ export const getInferredType = (
15
+ node: ts.Node,
16
+ checker: ts.TypeChecker
17
+ ): IrType | undefined => {
18
+ try {
19
+ // Try contextual type first (from assignment target, parameter, return, etc.)
20
+ // This is essential for empty arrays: [] has literal type never[] but contextual
21
+ // type Player[] when assigned to a Player[] variable
22
+ const expr = ts.isExpression(node) ? node : undefined;
23
+ const contextualType = expr ? checker.getContextualType(expr) : undefined;
24
+ const tsType = contextualType ?? checker.getTypeAtLocation(node);
25
+
26
+ const typeNode = checker.typeToTypeNode(
27
+ tsType,
28
+ node,
29
+ ts.NodeBuilderFlags.None
30
+ );
31
+ return typeNode ? convertType(typeNode, checker) : undefined;
32
+ } catch {
33
+ // If type extraction fails, return undefined
34
+ return undefined;
35
+ }
36
+ };
37
+
38
+ /**
39
+ * Extract type arguments from a call or new expression
40
+ * This captures both explicit type arguments and inferred ones
41
+ */
42
+ export const extractTypeArguments = (
43
+ node: ts.CallExpression | ts.NewExpression,
44
+ checker: ts.TypeChecker
45
+ ): readonly IrType[] | undefined => {
46
+ try {
47
+ // First check for explicit type arguments
48
+ if (node.typeArguments && node.typeArguments.length > 0) {
49
+ return node.typeArguments.map((typeArg) => convertType(typeArg, checker));
50
+ }
51
+
52
+ // Try to get inferred type arguments from resolved signature
53
+ const signature = checker.getResolvedSignature(node);
54
+ if (!signature) {
55
+ return undefined;
56
+ }
57
+
58
+ const typeParameters = signature.typeParameters;
59
+ if (!typeParameters || typeParameters.length === 0) {
60
+ return undefined;
61
+ }
62
+
63
+ // Get the type arguments inferred by the checker
64
+ const typeArgs: IrType[] = [];
65
+ for (const typeParam of typeParameters) {
66
+ // Try to resolve the instantiated type for this parameter
67
+ const typeNode = checker.typeToTypeNode(
68
+ typeParam as ts.Type,
69
+ node,
70
+ ts.NodeBuilderFlags.None
71
+ );
72
+ if (typeNode) {
73
+ typeArgs.push(convertType(typeNode, checker));
74
+ }
75
+ }
76
+
77
+ return typeArgs.length > 0 ? typeArgs : undefined;
78
+ } catch {
79
+ return undefined;
80
+ }
81
+ };
82
+
83
+ /**
84
+ * Check if a call/new expression requires specialization
85
+ * Returns true for conditional types, infer, variadic generics, this typing
86
+ */
87
+ export const checkIfRequiresSpecialization = (
88
+ node: ts.CallExpression | ts.NewExpression,
89
+ checker: ts.TypeChecker
90
+ ): boolean => {
91
+ try {
92
+ const signature = checker.getResolvedSignature(node);
93
+ if (!signature || !signature.declaration) {
94
+ return false;
95
+ }
96
+
97
+ const decl = signature.declaration;
98
+
99
+ // Check for conditional return types
100
+ if (
101
+ ts.isFunctionDeclaration(decl) ||
102
+ ts.isMethodDeclaration(decl) ||
103
+ ts.isFunctionTypeNode(decl)
104
+ ) {
105
+ if (decl.type && ts.isConditionalTypeNode(decl.type)) {
106
+ return true;
107
+ }
108
+ }
109
+
110
+ // Check for variadic type parameters (rest parameters with generic types)
111
+ const typeParameters = signature.typeParameters;
112
+ if (typeParameters) {
113
+ for (const typeParam of typeParameters) {
114
+ const constraint = typeParam.getConstraint();
115
+ if (constraint) {
116
+ const constraintStr = checker.typeToString(constraint);
117
+ // Check for unknown[] which indicates variadic
118
+ if (
119
+ constraintStr.includes("unknown[]") ||
120
+ constraintStr.includes("any[]")
121
+ ) {
122
+ return true;
123
+ }
124
+ }
125
+ }
126
+ }
127
+
128
+ return false;
129
+ } catch {
130
+ return false;
131
+ }
132
+ };
133
+
134
+ /**
135
+ * Convert TypeScript binary operator token to string
136
+ */
137
+ export const convertBinaryOperator = (
138
+ token: ts.BinaryOperatorToken
139
+ ): string => {
140
+ const operatorMap: Record<number, string> = {
141
+ [ts.SyntaxKind.PlusToken]: "+",
142
+ [ts.SyntaxKind.MinusToken]: "-",
143
+ [ts.SyntaxKind.AsteriskToken]: "*",
144
+ [ts.SyntaxKind.SlashToken]: "/",
145
+ [ts.SyntaxKind.PercentToken]: "%",
146
+ [ts.SyntaxKind.AsteriskAsteriskToken]: "**",
147
+ [ts.SyntaxKind.EqualsEqualsToken]: "==",
148
+ [ts.SyntaxKind.ExclamationEqualsToken]: "!=",
149
+ [ts.SyntaxKind.EqualsEqualsEqualsToken]: "===",
150
+ [ts.SyntaxKind.ExclamationEqualsEqualsToken]: "!==",
151
+ [ts.SyntaxKind.LessThanToken]: "<",
152
+ [ts.SyntaxKind.GreaterThanToken]: ">",
153
+ [ts.SyntaxKind.LessThanEqualsToken]: "<=",
154
+ [ts.SyntaxKind.GreaterThanEqualsToken]: ">=",
155
+ [ts.SyntaxKind.LessThanLessThanToken]: "<<",
156
+ [ts.SyntaxKind.GreaterThanGreaterThanToken]: ">>",
157
+ [ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken]: ">>>",
158
+ [ts.SyntaxKind.AmpersandToken]: "&",
159
+ [ts.SyntaxKind.BarToken]: "|",
160
+ [ts.SyntaxKind.CaretToken]: "^",
161
+ [ts.SyntaxKind.AmpersandAmpersandToken]: "&&",
162
+ [ts.SyntaxKind.BarBarToken]: "||",
163
+ [ts.SyntaxKind.QuestionQuestionToken]: "??",
164
+ [ts.SyntaxKind.InKeyword]: "in",
165
+ [ts.SyntaxKind.InstanceOfKeyword]: "instanceof",
166
+ [ts.SyntaxKind.EqualsToken]: "=",
167
+ [ts.SyntaxKind.PlusEqualsToken]: "+=",
168
+ [ts.SyntaxKind.MinusEqualsToken]: "-=",
169
+ [ts.SyntaxKind.AsteriskEqualsToken]: "*=",
170
+ [ts.SyntaxKind.SlashEqualsToken]: "/=",
171
+ [ts.SyntaxKind.PercentEqualsToken]: "%=",
172
+ [ts.SyntaxKind.AsteriskAsteriskEqualsToken]: "**=",
173
+ [ts.SyntaxKind.LessThanLessThanEqualsToken]: "<<=",
174
+ [ts.SyntaxKind.GreaterThanGreaterThanEqualsToken]: ">>=",
175
+ [ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken]: ">>>=",
176
+ [ts.SyntaxKind.AmpersandEqualsToken]: "&=",
177
+ [ts.SyntaxKind.BarEqualsToken]: "|=",
178
+ [ts.SyntaxKind.CaretEqualsToken]: "^=",
179
+ [ts.SyntaxKind.AmpersandAmpersandEqualsToken]: "&&=",
180
+ [ts.SyntaxKind.BarBarEqualsToken]: "||=",
181
+ [ts.SyntaxKind.QuestionQuestionEqualsToken]: "??=",
182
+ };
183
+
184
+ return operatorMap[token.kind] ?? "=";
185
+ };
186
+
187
+ /**
188
+ * Check if a binary operator token is an assignment operator
189
+ */
190
+ export const isAssignmentOperator = (
191
+ token: ts.BinaryOperatorToken
192
+ ): boolean => {
193
+ return (
194
+ token.kind >= ts.SyntaxKind.FirstAssignment &&
195
+ token.kind <= ts.SyntaxKind.LastAssignment
196
+ );
197
+ };
198
+
199
+ /**
200
+ * Get the contextual type for an expression (for object literals).
201
+ * Returns an IrType with type arguments if the contextual type is a named type
202
+ * (interface, class, generic), or undefined if it's an anonymous/primitive type.
203
+ *
204
+ * This captures the full type including generic type arguments (e.g., Container<T>),
205
+ * which is essential for emitting correct C# object initializers.
206
+ */
207
+ export const getContextualType = (
208
+ node: ts.Expression,
209
+ checker: ts.TypeChecker
210
+ ): IrType | undefined => {
211
+ try {
212
+ const contextualType = checker.getContextualType(node);
213
+ if (!contextualType) {
214
+ return undefined;
215
+ }
216
+
217
+ // Check if it's an object type with a symbol (named type)
218
+ const symbol = contextualType.getSymbol();
219
+ if (!symbol) {
220
+ return undefined;
221
+ }
222
+
223
+ // Get the symbol name
224
+ const name = symbol.getName();
225
+
226
+ // Skip anonymous types and built-in types
227
+ if (name === "__type" || name === "__object" || name === "Object") {
228
+ return undefined;
229
+ }
230
+
231
+ // Check that it's actually a class or interface declaration
232
+ const declarations = symbol.getDeclarations();
233
+ if (declarations && declarations.length > 0) {
234
+ const firstDecl = declarations[0];
235
+ if (
236
+ firstDecl &&
237
+ (ts.isInterfaceDeclaration(firstDecl) ||
238
+ ts.isClassDeclaration(firstDecl) ||
239
+ ts.isTypeAliasDeclaration(firstDecl))
240
+ ) {
241
+ // Convert the full contextual type to IR, capturing type arguments
242
+ return convertTsTypeToIr(contextualType, checker);
243
+ }
244
+ }
245
+
246
+ return undefined;
247
+ } catch {
248
+ return undefined;
249
+ }
250
+ };
251
+
252
+ /**
253
+ * @deprecated Use getContextualType instead - returns IrType with type arguments
254
+ */
255
+ export const getContextualTypeName = (
256
+ node: ts.Expression,
257
+ checker: ts.TypeChecker
258
+ ): string | undefined => {
259
+ const irType = getContextualType(node, checker);
260
+ if (irType && irType.kind === "referenceType") {
261
+ return irType.name;
262
+ }
263
+ return undefined;
264
+ };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Expression converters barrel exports
3
+ */
4
+
5
+ // Helpers
6
+ export {
7
+ getInferredType,
8
+ extractTypeArguments,
9
+ checkIfRequiresSpecialization,
10
+ convertBinaryOperator,
11
+ isAssignmentOperator,
12
+ } from "./helpers.js";
13
+
14
+ // Literals
15
+ export { convertLiteral } from "./literals.js";
16
+
17
+ // Collections
18
+ export { convertArrayLiteral, convertObjectLiteral } from "./collections.js";
19
+
20
+ // Member access
21
+ export { convertMemberExpression } from "./access.js";
22
+
23
+ // Calls
24
+ export { convertCallExpression, convertNewExpression } from "./calls.js";
25
+
26
+ // Operators
27
+ export {
28
+ convertBinaryExpression,
29
+ convertUnaryExpression,
30
+ convertUpdateExpression,
31
+ } from "./operators.js";
32
+
33
+ // Functions
34
+ export {
35
+ convertFunctionExpression,
36
+ convertArrowFunction,
37
+ } from "./functions.js";
38
+
39
+ // Other
40
+ export {
41
+ convertConditionalExpression,
42
+ convertTemplateLiteral,
43
+ } from "./other.js";
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Literal expression converters
3
+ */
4
+
5
+ import * as ts from "typescript";
6
+ import { IrLiteralExpression } from "../../types.js";
7
+ import { getInferredType } from "./helpers.js";
8
+
9
+ /**
10
+ * Convert string or numeric literal
11
+ */
12
+ export const convertLiteral = (
13
+ node: ts.StringLiteral | ts.NumericLiteral,
14
+ checker: ts.TypeChecker
15
+ ): IrLiteralExpression => {
16
+ return {
17
+ kind: "literal",
18
+ value: ts.isStringLiteral(node) ? node.text : Number(node.text),
19
+ raw: node.getText(),
20
+ inferredType: getInferredType(node, checker),
21
+ };
22
+ };