@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,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Class declaration conversion orchestrator
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as ts from "typescript";
|
|
6
|
+
import { IrClassDeclaration, IrClassMember } from "../../../../types.js";
|
|
7
|
+
import { convertExpression } from "../../../../expression-converter.js";
|
|
8
|
+
import { convertType } from "../../../../type-converter.js";
|
|
9
|
+
import { hasExportModifier, convertTypeParameters } from "../../helpers.js";
|
|
10
|
+
import { convertProperty } from "./properties.js";
|
|
11
|
+
import { convertMethod } from "./methods.js";
|
|
12
|
+
import {
|
|
13
|
+
convertConstructor,
|
|
14
|
+
extractParameterProperties,
|
|
15
|
+
} from "./constructors.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Convert a single class member
|
|
19
|
+
*/
|
|
20
|
+
const convertClassMember = (
|
|
21
|
+
node: ts.ClassElement,
|
|
22
|
+
checker: ts.TypeChecker,
|
|
23
|
+
superClass: ts.ExpressionWithTypeArguments | undefined,
|
|
24
|
+
constructorParams?: ts.NodeArray<ts.ParameterDeclaration>
|
|
25
|
+
): IrClassMember | null => {
|
|
26
|
+
if (ts.isPropertyDeclaration(node)) {
|
|
27
|
+
return convertProperty(node, checker, superClass);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (ts.isMethodDeclaration(node)) {
|
|
31
|
+
return convertMethod(node, checker, superClass);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (ts.isConstructorDeclaration(node)) {
|
|
35
|
+
return convertConstructor(node, checker, constructorParams);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return null;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Filter members to only include those declared directly on this class
|
|
43
|
+
*/
|
|
44
|
+
const filterOwnMembers = (
|
|
45
|
+
node: ts.ClassDeclaration,
|
|
46
|
+
checker: ts.TypeChecker
|
|
47
|
+
): readonly ts.ClassElement[] => {
|
|
48
|
+
return node.members.filter((m) => {
|
|
49
|
+
// Always include constructors and methods declared on this class
|
|
50
|
+
if (ts.isConstructorDeclaration(m) || ts.isMethodDeclaration(m)) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
// For properties, only include if they're declared directly on this class
|
|
54
|
+
if (ts.isPropertyDeclaration(m)) {
|
|
55
|
+
// Check if this property has a declaration on this specific class node
|
|
56
|
+
const symbol = checker.getSymbolAtLocation(m.name);
|
|
57
|
+
if (!symbol) return true; // Include if we can't determine
|
|
58
|
+
const declarations = symbol.getDeclarations() || [];
|
|
59
|
+
// Only include if this exact node is in the declarations
|
|
60
|
+
return declarations.some((d) => d === m);
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Deduplicate members by name, keeping first occurrence
|
|
68
|
+
*/
|
|
69
|
+
const deduplicateMembers = (
|
|
70
|
+
members: readonly IrClassMember[]
|
|
71
|
+
): readonly IrClassMember[] => {
|
|
72
|
+
const seenNames = new Set<string>();
|
|
73
|
+
return members.filter((member) => {
|
|
74
|
+
if (member.kind === "constructorDeclaration") {
|
|
75
|
+
return true; // Always include constructor
|
|
76
|
+
}
|
|
77
|
+
const name =
|
|
78
|
+
member.kind === "propertyDeclaration" ||
|
|
79
|
+
member.kind === "methodDeclaration"
|
|
80
|
+
? member.name
|
|
81
|
+
: null;
|
|
82
|
+
if (!name) return true;
|
|
83
|
+
if (seenNames.has(name)) {
|
|
84
|
+
return false; // Skip duplicate
|
|
85
|
+
}
|
|
86
|
+
seenNames.add(name);
|
|
87
|
+
return true;
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Check if a type reference is the struct marker
|
|
93
|
+
*/
|
|
94
|
+
const isStructMarker = (
|
|
95
|
+
typeRef: ts.ExpressionWithTypeArguments,
|
|
96
|
+
checker: ts.TypeChecker
|
|
97
|
+
): boolean => {
|
|
98
|
+
const symbol = checker.getSymbolAtLocation(typeRef.expression);
|
|
99
|
+
return symbol?.escapedName === "struct" || symbol?.escapedName === "Struct";
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Convert class declaration to IR
|
|
104
|
+
*/
|
|
105
|
+
export const convertClassDeclaration = (
|
|
106
|
+
node: ts.ClassDeclaration,
|
|
107
|
+
checker: ts.TypeChecker
|
|
108
|
+
): IrClassDeclaration | null => {
|
|
109
|
+
if (!node.name) return null;
|
|
110
|
+
|
|
111
|
+
const superClass = node.heritageClauses?.find(
|
|
112
|
+
(h) => h.token === ts.SyntaxKind.ExtendsKeyword
|
|
113
|
+
)?.types[0];
|
|
114
|
+
|
|
115
|
+
// Detect struct marker in implements clause
|
|
116
|
+
let isStruct = false;
|
|
117
|
+
const implementsClause = node.heritageClauses?.find(
|
|
118
|
+
(h) => h.token === ts.SyntaxKind.ImplementsKeyword
|
|
119
|
+
);
|
|
120
|
+
const implementsTypes =
|
|
121
|
+
implementsClause?.types
|
|
122
|
+
.filter((t) => {
|
|
123
|
+
if (isStructMarker(t, checker)) {
|
|
124
|
+
isStruct = true;
|
|
125
|
+
return false; // Remove marker from implements
|
|
126
|
+
}
|
|
127
|
+
return true;
|
|
128
|
+
})
|
|
129
|
+
.map((t) => convertType(t, checker)) ?? [];
|
|
130
|
+
|
|
131
|
+
// Extract parameter properties from constructor
|
|
132
|
+
const constructor = node.members.find(ts.isConstructorDeclaration);
|
|
133
|
+
const parameterProperties = extractParameterProperties(constructor, checker);
|
|
134
|
+
|
|
135
|
+
// Filter to only include members declared directly on this class (not inherited)
|
|
136
|
+
const ownMembers = filterOwnMembers(node, checker);
|
|
137
|
+
|
|
138
|
+
const convertedMembers = ownMembers
|
|
139
|
+
.map((m) =>
|
|
140
|
+
convertClassMember(m, checker, superClass, constructor?.parameters)
|
|
141
|
+
)
|
|
142
|
+
.filter((m): m is IrClassMember => m !== null);
|
|
143
|
+
|
|
144
|
+
// Deduplicate members by name (keep first occurrence)
|
|
145
|
+
// Parameter properties should take precedence over regular properties with same name
|
|
146
|
+
const allMembers = [...parameterProperties, ...convertedMembers];
|
|
147
|
+
const deduplicatedMembers = deduplicateMembers(allMembers);
|
|
148
|
+
|
|
149
|
+
// Filter out __brand property if this is a struct
|
|
150
|
+
const finalMembers = isStruct
|
|
151
|
+
? deduplicatedMembers.filter(
|
|
152
|
+
(m) => m.kind !== "propertyDeclaration" || m.name !== "__brand"
|
|
153
|
+
)
|
|
154
|
+
: deduplicatedMembers;
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
kind: "classDeclaration",
|
|
158
|
+
name: node.name.text,
|
|
159
|
+
typeParameters: convertTypeParameters(node.typeParameters, checker),
|
|
160
|
+
superClass: superClass ? convertExpression(superClass, checker) : undefined,
|
|
161
|
+
implements: implementsTypes,
|
|
162
|
+
members: finalMembers,
|
|
163
|
+
isExported: hasExportModifier(node),
|
|
164
|
+
isStruct,
|
|
165
|
+
};
|
|
166
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Override detection for class members
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as ts from "typescript";
|
|
6
|
+
import { getMetadataRegistry } from "../registry.js";
|
|
7
|
+
|
|
8
|
+
export type OverrideInfo = {
|
|
9
|
+
readonly isOverride: boolean;
|
|
10
|
+
readonly isShadow: boolean;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Check if a method/property should be marked as override based on base class metadata
|
|
15
|
+
*/
|
|
16
|
+
export const detectOverride = (
|
|
17
|
+
memberName: string,
|
|
18
|
+
memberKind: "method" | "property",
|
|
19
|
+
superClass: ts.ExpressionWithTypeArguments | undefined,
|
|
20
|
+
checker: ts.TypeChecker,
|
|
21
|
+
parameterTypes?: readonly string[]
|
|
22
|
+
): OverrideInfo => {
|
|
23
|
+
if (!superClass) {
|
|
24
|
+
return { isOverride: false, isShadow: false };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Resolve the base class type
|
|
28
|
+
const baseType = checker.getTypeAtLocation(superClass.expression);
|
|
29
|
+
const baseSymbol = baseType.getSymbol();
|
|
30
|
+
|
|
31
|
+
if (!baseSymbol) {
|
|
32
|
+
return { isOverride: false, isShadow: false };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Get fully-qualified name for .NET types
|
|
36
|
+
const qualifiedName = checker.getFullyQualifiedName(baseSymbol);
|
|
37
|
+
|
|
38
|
+
// Check if this is a .NET type (starts with "System." or other .NET namespaces)
|
|
39
|
+
const isDotNetType =
|
|
40
|
+
qualifiedName.startsWith("System.") ||
|
|
41
|
+
qualifiedName.startsWith("Microsoft.") ||
|
|
42
|
+
qualifiedName.startsWith("Tsonic.Runtime.");
|
|
43
|
+
|
|
44
|
+
if (isDotNetType) {
|
|
45
|
+
return detectDotNetOverride(
|
|
46
|
+
memberName,
|
|
47
|
+
memberKind,
|
|
48
|
+
qualifiedName,
|
|
49
|
+
parameterTypes
|
|
50
|
+
);
|
|
51
|
+
} else {
|
|
52
|
+
return detectTypeScriptOverride(memberName, memberKind, baseSymbol);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Detect override for .NET base classes using metadata
|
|
58
|
+
*/
|
|
59
|
+
const detectDotNetOverride = (
|
|
60
|
+
memberName: string,
|
|
61
|
+
memberKind: "method" | "property",
|
|
62
|
+
qualifiedName: string,
|
|
63
|
+
parameterTypes?: readonly string[]
|
|
64
|
+
): OverrideInfo => {
|
|
65
|
+
const metadata = getMetadataRegistry();
|
|
66
|
+
|
|
67
|
+
if (memberKind === "method" && parameterTypes) {
|
|
68
|
+
const signature = `${memberName}(${parameterTypes.join(",")})`;
|
|
69
|
+
const isVirtual = metadata.isVirtualMember(qualifiedName, signature);
|
|
70
|
+
const isSealed = metadata.isSealedMember(qualifiedName, signature);
|
|
71
|
+
return { isOverride: isVirtual && !isSealed, isShadow: !isVirtual };
|
|
72
|
+
} else if (memberKind === "property") {
|
|
73
|
+
// For properties, check without parameters
|
|
74
|
+
const isVirtual = metadata.isVirtualMember(qualifiedName, memberName);
|
|
75
|
+
const isSealed = metadata.isSealedMember(qualifiedName, memberName);
|
|
76
|
+
return { isOverride: isVirtual && !isSealed, isShadow: !isVirtual };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return { isOverride: false, isShadow: false };
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Detect override for TypeScript base classes
|
|
84
|
+
*/
|
|
85
|
+
const detectTypeScriptOverride = (
|
|
86
|
+
memberName: string,
|
|
87
|
+
memberKind: "method" | "property",
|
|
88
|
+
baseSymbol: ts.Symbol
|
|
89
|
+
): OverrideInfo => {
|
|
90
|
+
const baseDeclarations = baseSymbol.getDeclarations();
|
|
91
|
+
|
|
92
|
+
if (!baseDeclarations || baseDeclarations.length === 0) {
|
|
93
|
+
return { isOverride: false, isShadow: false };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
for (const baseDecl of baseDeclarations) {
|
|
97
|
+
if (ts.isClassDeclaration(baseDecl)) {
|
|
98
|
+
// Check if base class has this member
|
|
99
|
+
const baseMember = baseDecl.members.find((m) => {
|
|
100
|
+
if (memberKind === "method" && ts.isMethodDeclaration(m)) {
|
|
101
|
+
return ts.isIdentifier(m.name) && m.name.text === memberName;
|
|
102
|
+
} else if (memberKind === "property" && ts.isPropertyDeclaration(m)) {
|
|
103
|
+
return ts.isIdentifier(m.name) && m.name.text === memberName;
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
if (baseMember) {
|
|
109
|
+
// In TypeScript, all methods can be overridden unless final (not supported in TS)
|
|
110
|
+
return { isOverride: true, isShadow: false };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return { isOverride: false, isShadow: false };
|
|
116
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Property member conversion
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as ts from "typescript";
|
|
6
|
+
import { IrClassMember } from "../../../../types.js";
|
|
7
|
+
import { convertExpression } from "../../../../expression-converter.js";
|
|
8
|
+
import { convertType, inferType } from "../../../../type-converter.js";
|
|
9
|
+
import {
|
|
10
|
+
hasStaticModifier,
|
|
11
|
+
hasReadonlyModifier,
|
|
12
|
+
getAccessibility,
|
|
13
|
+
} from "../../helpers.js";
|
|
14
|
+
import { detectOverride } from "./override-detection.js";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get the IR type for a property declaration.
|
|
18
|
+
* Uses explicit annotation if present, otherwise infers from TypeChecker.
|
|
19
|
+
* C# requires explicit types for class fields (no 'var').
|
|
20
|
+
*/
|
|
21
|
+
const getPropertyType = (
|
|
22
|
+
node: ts.PropertyDeclaration,
|
|
23
|
+
checker: ts.TypeChecker
|
|
24
|
+
) => {
|
|
25
|
+
// If there's an explicit type annotation, use it
|
|
26
|
+
if (node.type) {
|
|
27
|
+
return convertType(node.type, checker);
|
|
28
|
+
}
|
|
29
|
+
// Infer type from checker (always needed for class fields)
|
|
30
|
+
return inferType(node, checker);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Convert property declaration to IR
|
|
35
|
+
*/
|
|
36
|
+
export const convertProperty = (
|
|
37
|
+
node: ts.PropertyDeclaration,
|
|
38
|
+
checker: ts.TypeChecker,
|
|
39
|
+
superClass: ts.ExpressionWithTypeArguments | undefined
|
|
40
|
+
): IrClassMember => {
|
|
41
|
+
const memberName = ts.isIdentifier(node.name) ? node.name.text : "[computed]";
|
|
42
|
+
|
|
43
|
+
const overrideInfo = detectOverride(
|
|
44
|
+
memberName,
|
|
45
|
+
"property",
|
|
46
|
+
superClass,
|
|
47
|
+
checker
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
kind: "propertyDeclaration",
|
|
52
|
+
name: memberName,
|
|
53
|
+
type: getPropertyType(node, checker),
|
|
54
|
+
initializer: node.initializer
|
|
55
|
+
? convertExpression(node.initializer, checker)
|
|
56
|
+
: undefined,
|
|
57
|
+
isStatic: hasStaticModifier(node),
|
|
58
|
+
isReadonly: hasReadonlyModifier(node),
|
|
59
|
+
accessibility: getAccessibility(node),
|
|
60
|
+
isOverride: overrideInfo.isOverride ? true : undefined,
|
|
61
|
+
isShadow: overrideInfo.isShadow ? true : undefined,
|
|
62
|
+
};
|
|
63
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enum declaration converter
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as ts from "typescript";
|
|
6
|
+
import { IrEnumDeclaration } from "../../../types.js";
|
|
7
|
+
import { convertExpression } from "../../../expression-converter.js";
|
|
8
|
+
import { hasExportModifier } from "../helpers.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Convert enum declaration
|
|
12
|
+
*/
|
|
13
|
+
export const convertEnumDeclaration = (
|
|
14
|
+
node: ts.EnumDeclaration,
|
|
15
|
+
checker: ts.TypeChecker
|
|
16
|
+
): IrEnumDeclaration => {
|
|
17
|
+
return {
|
|
18
|
+
kind: "enumDeclaration",
|
|
19
|
+
name: node.name.text,
|
|
20
|
+
members: node.members.map((m) => ({
|
|
21
|
+
kind: "enumMember" as const,
|
|
22
|
+
name: ts.isIdentifier(m.name) ? m.name.text : "[computed]",
|
|
23
|
+
initializer: m.initializer
|
|
24
|
+
? convertExpression(m.initializer, checker)
|
|
25
|
+
: undefined,
|
|
26
|
+
})),
|
|
27
|
+
isExported: hasExportModifier(node),
|
|
28
|
+
};
|
|
29
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Function declaration converter
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as ts from "typescript";
|
|
6
|
+
import { IrFunctionDeclaration } from "../../../types.js";
|
|
7
|
+
import { convertType } from "../../../type-converter.js";
|
|
8
|
+
import { convertBlockStatement } from "../control.js";
|
|
9
|
+
import {
|
|
10
|
+
hasExportModifier,
|
|
11
|
+
convertTypeParameters,
|
|
12
|
+
convertParameters,
|
|
13
|
+
} from "../helpers.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Convert function declaration
|
|
17
|
+
*/
|
|
18
|
+
export const convertFunctionDeclaration = (
|
|
19
|
+
node: ts.FunctionDeclaration,
|
|
20
|
+
checker: ts.TypeChecker
|
|
21
|
+
): IrFunctionDeclaration | null => {
|
|
22
|
+
if (!node.name) return null;
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
kind: "functionDeclaration",
|
|
26
|
+
name: node.name.text,
|
|
27
|
+
typeParameters: convertTypeParameters(node.typeParameters, checker),
|
|
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
|
+
isExported: hasExportModifier(node),
|
|
38
|
+
};
|
|
39
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declaration converters - Public API
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { setMetadataRegistry, setBindingRegistry } from "./registry.js";
|
|
6
|
+
export { convertVariableStatement } from "./variables.js";
|
|
7
|
+
export { convertFunctionDeclaration } from "./functions.js";
|
|
8
|
+
export { convertClassDeclaration } from "./classes.js";
|
|
9
|
+
export {
|
|
10
|
+
convertInterfaceDeclaration,
|
|
11
|
+
convertInterfaceMember,
|
|
12
|
+
} from "./interfaces.js";
|
|
13
|
+
export { convertEnumDeclaration } from "./enums.js";
|
|
14
|
+
export { convertTypeAliasDeclaration } from "./type-aliases.js";
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interface declaration converter
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as ts from "typescript";
|
|
6
|
+
import { IrInterfaceDeclaration, IrInterfaceMember } from "../../../types.js";
|
|
7
|
+
import { convertType } from "../../../type-converter.js";
|
|
8
|
+
import {
|
|
9
|
+
hasExportModifier,
|
|
10
|
+
hasReadonlyModifier,
|
|
11
|
+
convertTypeParameters,
|
|
12
|
+
convertParameters,
|
|
13
|
+
} from "../helpers.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Convert interface member
|
|
17
|
+
*/
|
|
18
|
+
export const convertInterfaceMember = (
|
|
19
|
+
node: ts.TypeElement,
|
|
20
|
+
checker: ts.TypeChecker
|
|
21
|
+
): IrInterfaceMember | null => {
|
|
22
|
+
if (ts.isPropertySignature(node) && node.type) {
|
|
23
|
+
return {
|
|
24
|
+
kind: "propertySignature",
|
|
25
|
+
name:
|
|
26
|
+
node.name && ts.isIdentifier(node.name) ? node.name.text : "[computed]",
|
|
27
|
+
type: convertType(node.type, checker),
|
|
28
|
+
isOptional: !!node.questionToken,
|
|
29
|
+
isReadonly: hasReadonlyModifier(node),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (ts.isMethodSignature(node)) {
|
|
34
|
+
return {
|
|
35
|
+
kind: "methodSignature",
|
|
36
|
+
name:
|
|
37
|
+
node.name && ts.isIdentifier(node.name) ? node.name.text : "[computed]",
|
|
38
|
+
typeParameters: convertTypeParameters(node.typeParameters, checker),
|
|
39
|
+
parameters: convertParameters(node.parameters, checker),
|
|
40
|
+
returnType: node.type ? convertType(node.type, checker) : undefined,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return null;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Check if a type reference is the struct marker
|
|
49
|
+
*/
|
|
50
|
+
const isStructMarker = (
|
|
51
|
+
typeRef: ts.ExpressionWithTypeArguments,
|
|
52
|
+
checker: ts.TypeChecker
|
|
53
|
+
): boolean => {
|
|
54
|
+
const symbol = checker.getSymbolAtLocation(typeRef.expression);
|
|
55
|
+
return symbol?.escapedName === "struct" || symbol?.escapedName === "Struct";
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Check if an interface declaration IS the struct marker itself (should be filtered out)
|
|
60
|
+
*/
|
|
61
|
+
const isMarkerInterface = (node: ts.InterfaceDeclaration): boolean => {
|
|
62
|
+
const name = node.name.text;
|
|
63
|
+
if (name !== "struct" && name !== "Struct") {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Check if it has only the __brand property
|
|
68
|
+
const members = node.members;
|
|
69
|
+
if (members.length !== 1) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const member = members[0];
|
|
74
|
+
if (!member || !ts.isPropertySignature(member)) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const memberName =
|
|
79
|
+
member.name && ts.isIdentifier(member.name) ? member.name.text : "";
|
|
80
|
+
return memberName === "__brand";
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Convert interface declaration
|
|
85
|
+
* Returns null for marker interfaces that should be filtered out
|
|
86
|
+
*/
|
|
87
|
+
export const convertInterfaceDeclaration = (
|
|
88
|
+
node: ts.InterfaceDeclaration,
|
|
89
|
+
checker: ts.TypeChecker
|
|
90
|
+
): IrInterfaceDeclaration | null => {
|
|
91
|
+
// Filter out marker interfaces completely
|
|
92
|
+
if (isMarkerInterface(node)) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
// Detect struct marker in extends clause
|
|
96
|
+
let isStruct = false;
|
|
97
|
+
const extendsClause = node.heritageClauses?.find(
|
|
98
|
+
(h) => h.token === ts.SyntaxKind.ExtendsKeyword
|
|
99
|
+
);
|
|
100
|
+
const extendsTypes =
|
|
101
|
+
extendsClause?.types
|
|
102
|
+
.filter((t) => {
|
|
103
|
+
if (isStructMarker(t, checker)) {
|
|
104
|
+
isStruct = true;
|
|
105
|
+
return false; // Remove marker from extends
|
|
106
|
+
}
|
|
107
|
+
return true;
|
|
108
|
+
})
|
|
109
|
+
.map((t) => convertType(t, checker)) ?? [];
|
|
110
|
+
|
|
111
|
+
const allMembers = node.members
|
|
112
|
+
.map((m) => convertInterfaceMember(m, checker))
|
|
113
|
+
.filter((m): m is IrInterfaceMember => m !== null);
|
|
114
|
+
|
|
115
|
+
// Filter out __brand property if this is a struct
|
|
116
|
+
const finalMembers = isStruct
|
|
117
|
+
? allMembers.filter(
|
|
118
|
+
(m) => m.kind !== "propertySignature" || m.name !== "__brand"
|
|
119
|
+
)
|
|
120
|
+
: allMembers;
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
kind: "interfaceDeclaration",
|
|
124
|
+
name: node.name.text,
|
|
125
|
+
typeParameters: convertTypeParameters(node.typeParameters, checker),
|
|
126
|
+
extends: extendsTypes,
|
|
127
|
+
members: finalMembers,
|
|
128
|
+
isExported: hasExportModifier(node),
|
|
129
|
+
isStruct,
|
|
130
|
+
};
|
|
131
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Metadata and binding registry management
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { DotnetMetadataRegistry } from "../../../../dotnet-metadata.js";
|
|
6
|
+
import { BindingRegistry } from "../../../../program/bindings.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Module-level metadata registry singleton
|
|
10
|
+
* Set once at the start of compilation via setMetadataRegistry()
|
|
11
|
+
*/
|
|
12
|
+
let _metadataRegistry: DotnetMetadataRegistry = new DotnetMetadataRegistry();
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Module-level binding registry singleton
|
|
16
|
+
* Set once at the start of compilation via setBindingRegistry()
|
|
17
|
+
*/
|
|
18
|
+
let _bindingRegistry: BindingRegistry = new BindingRegistry();
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Set the metadata registry for this compilation
|
|
22
|
+
* Called once at the start of IR building
|
|
23
|
+
*/
|
|
24
|
+
export const setMetadataRegistry = (registry: DotnetMetadataRegistry): void => {
|
|
25
|
+
_metadataRegistry = registry;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Get the current metadata registry
|
|
30
|
+
*/
|
|
31
|
+
export const getMetadataRegistry = (): DotnetMetadataRegistry =>
|
|
32
|
+
_metadataRegistry;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Set the binding registry for this compilation
|
|
36
|
+
* Called once at the start of IR building
|
|
37
|
+
*/
|
|
38
|
+
export const setBindingRegistry = (registry: BindingRegistry): void => {
|
|
39
|
+
_bindingRegistry = registry;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Get the current binding registry
|
|
44
|
+
*/
|
|
45
|
+
export const getBindingRegistry = (): BindingRegistry => _bindingRegistry;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type alias declaration converter
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as ts from "typescript";
|
|
6
|
+
import { IrTypeAliasDeclaration } from "../../../types.js";
|
|
7
|
+
import { convertType } from "../../../type-converter.js";
|
|
8
|
+
import { hasExportModifier, convertTypeParameters } from "../helpers.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Convert type alias declaration
|
|
12
|
+
*/
|
|
13
|
+
export const convertTypeAliasDeclaration = (
|
|
14
|
+
node: ts.TypeAliasDeclaration,
|
|
15
|
+
checker: ts.TypeChecker
|
|
16
|
+
): IrTypeAliasDeclaration => {
|
|
17
|
+
return {
|
|
18
|
+
kind: "typeAliasDeclaration",
|
|
19
|
+
name: node.name.text,
|
|
20
|
+
typeParameters: convertTypeParameters(node.typeParameters, checker),
|
|
21
|
+
type: convertType(node.type, checker),
|
|
22
|
+
isExported: hasExportModifier(node),
|
|
23
|
+
isStruct: false, // Type aliases are not structs by default
|
|
24
|
+
};
|
|
25
|
+
};
|