@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.
- package/package.json +53 -0
- package/src/dependency-graph.ts +18 -0
- package/src/dotnet-metadata.ts +121 -0
- package/src/graph/builder.ts +81 -0
- package/src/graph/circular.ts +58 -0
- package/src/graph/extraction/exports.ts +55 -0
- package/src/graph/extraction/imports.ts +81 -0
- package/src/graph/extraction/index.ts +7 -0
- package/src/graph/extraction/orchestrator.ts +99 -0
- package/src/graph/extraction.ts +10 -0
- package/src/graph/helpers.ts +51 -0
- package/src/graph/index.ts +17 -0
- package/src/graph/types.ts +13 -0
- package/src/index.ts +80 -0
- package/src/ir/binding-resolution.test.ts +585 -0
- package/src/ir/builder/exports.ts +78 -0
- package/src/ir/builder/helpers.ts +27 -0
- package/src/ir/builder/imports.ts +153 -0
- package/src/ir/builder/index.ts +10 -0
- package/src/ir/builder/orchestrator.ts +178 -0
- package/src/ir/builder/statements.ts +55 -0
- package/src/ir/builder/types.ts +8 -0
- package/src/ir/builder/validation.ts +129 -0
- package/src/ir/builder.test.ts +581 -0
- package/src/ir/builder.ts +14 -0
- package/src/ir/converters/expressions/access.ts +99 -0
- package/src/ir/converters/expressions/calls.ts +137 -0
- package/src/ir/converters/expressions/collections.ts +84 -0
- package/src/ir/converters/expressions/functions.ts +62 -0
- package/src/ir/converters/expressions/helpers.ts +264 -0
- package/src/ir/converters/expressions/index.ts +43 -0
- package/src/ir/converters/expressions/literals.ts +22 -0
- package/src/ir/converters/expressions/operators.ts +147 -0
- package/src/ir/converters/expressions/other.ts +60 -0
- package/src/ir/converters/statements/control/blocks.ts +22 -0
- package/src/ir/converters/statements/control/conditionals.ts +67 -0
- package/src/ir/converters/statements/control/exceptions.ts +43 -0
- package/src/ir/converters/statements/control/index.ts +17 -0
- package/src/ir/converters/statements/control/loops.ts +99 -0
- package/src/ir/converters/statements/control.ts +17 -0
- package/src/ir/converters/statements/declarations/classes/constructors.ts +120 -0
- package/src/ir/converters/statements/declarations/classes/index.ts +12 -0
- package/src/ir/converters/statements/declarations/classes/methods.ts +61 -0
- package/src/ir/converters/statements/declarations/classes/orchestrator.ts +166 -0
- package/src/ir/converters/statements/declarations/classes/override-detection.ts +116 -0
- package/src/ir/converters/statements/declarations/classes/properties.ts +63 -0
- package/src/ir/converters/statements/declarations/classes.ts +6 -0
- package/src/ir/converters/statements/declarations/enums.ts +29 -0
- package/src/ir/converters/statements/declarations/functions.ts +39 -0
- package/src/ir/converters/statements/declarations/index.ts +14 -0
- package/src/ir/converters/statements/declarations/interfaces.ts +131 -0
- package/src/ir/converters/statements/declarations/registry.ts +45 -0
- package/src/ir/converters/statements/declarations/type-aliases.ts +25 -0
- package/src/ir/converters/statements/declarations/variables.ts +60 -0
- package/src/ir/converters/statements/declarations.ts +16 -0
- package/src/ir/converters/statements/helpers.ts +174 -0
- package/src/ir/converters/statements/index.ts +40 -0
- package/src/ir/expression-converter.ts +207 -0
- package/src/ir/generic-validator.ts +100 -0
- package/src/ir/hierarchical-bindings-e2e.test.ts +163 -0
- package/src/ir/index.ts +6 -0
- package/src/ir/statement-converter.ts +128 -0
- package/src/ir/type-converter/arrays.ts +20 -0
- package/src/ir/type-converter/converter.ts +10 -0
- package/src/ir/type-converter/functions.ts +22 -0
- package/src/ir/type-converter/index.ts +11 -0
- package/src/ir/type-converter/inference.ts +122 -0
- package/src/ir/type-converter/literals.ts +40 -0
- package/src/ir/type-converter/objects.ts +107 -0
- package/src/ir/type-converter/orchestrator.ts +85 -0
- package/src/ir/type-converter/patterns.ts +73 -0
- package/src/ir/type-converter/primitives.ts +57 -0
- package/src/ir/type-converter/references.ts +64 -0
- package/src/ir/type-converter/unions-intersections.ts +34 -0
- package/src/ir/type-converter.ts +13 -0
- package/src/ir/types/expressions.ts +215 -0
- package/src/ir/types/guards.ts +39 -0
- package/src/ir/types/helpers.ts +135 -0
- package/src/ir/types/index.ts +108 -0
- package/src/ir/types/ir-types.ts +96 -0
- package/src/ir/types/module.ts +57 -0
- package/src/ir/types/statements.ts +238 -0
- package/src/ir/types.ts +97 -0
- package/src/metadata/bindings-loader.test.ts +144 -0
- package/src/metadata/bindings-loader.ts +357 -0
- package/src/metadata/index.ts +15 -0
- package/src/metadata/library-loader.ts +153 -0
- package/src/metadata/loader.test.ts +156 -0
- package/src/metadata/loader.ts +382 -0
- package/src/program/bindings.test.ts +512 -0
- package/src/program/bindings.ts +253 -0
- package/src/program/config.ts +30 -0
- package/src/program/creation.ts +249 -0
- package/src/program/dependency-graph.ts +245 -0
- package/src/program/diagnostics.ts +103 -0
- package/src/program/index.ts +19 -0
- package/src/program/metadata.ts +68 -0
- package/src/program/queries.ts +18 -0
- package/src/program/types.ts +38 -0
- package/src/program.ts +13 -0
- package/src/resolver/dotnet-import-resolver.ts +226 -0
- package/src/resolver/import-resolution.ts +177 -0
- package/src/resolver/index.ts +18 -0
- package/src/resolver/namespace.test.ts +86 -0
- package/src/resolver/namespace.ts +42 -0
- package/src/resolver/naming.ts +38 -0
- package/src/resolver/path-resolution.ts +22 -0
- package/src/resolver/types.ts +15 -0
- package/src/resolver.test.ts +155 -0
- package/src/resolver.ts +14 -0
- package/src/symbol-table/builder.ts +114 -0
- package/src/symbol-table/creation.ts +42 -0
- package/src/symbol-table/helpers.ts +18 -0
- package/src/symbol-table/index.ts +13 -0
- package/src/symbol-table/queries.ts +42 -0
- package/src/symbol-table/types.ts +28 -0
- package/src/symbol-table.ts +14 -0
- package/src/types/bindings.ts +172 -0
- package/src/types/diagnostic.test.ts +164 -0
- package/src/types/diagnostic.ts +153 -0
- package/src/types/explicit-views.test.ts +113 -0
- package/src/types/explicit-views.ts +218 -0
- package/src/types/metadata.ts +229 -0
- package/src/types/module.ts +99 -0
- package/src/types/nested-types.test.ts +194 -0
- package/src/types/nested-types.ts +215 -0
- package/src/types/parameter-modifiers.ts +173 -0
- package/src/types/ref-parameters.test.ts +192 -0
- package/src/types/ref-parameters.ts +268 -0
- package/src/types/result.test.ts +157 -0
- package/src/types/result.ts +48 -0
- package/src/types/support-types.test.ts +81 -0
- package/src/types/support-types.ts +288 -0
- package/src/types/test-harness.ts +180 -0
- package/src/validation/exports.ts +98 -0
- package/src/validation/features.ts +89 -0
- package/src/validation/generics.ts +40 -0
- package/src/validation/helpers.ts +31 -0
- package/src/validation/imports.ts +97 -0
- package/src/validation/index.ts +11 -0
- package/src/validation/orchestrator.ts +51 -0
- package/src/validation/static-safety.ts +267 -0
- package/src/validator.test.ts +468 -0
- package/src/validator.ts +15 -0
- 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
|
+
};
|