@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,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,6 @@
1
+ /**
2
+ * Class declaration converter
3
+ * Main dispatcher - re-exports from classes/ subdirectory
4
+ */
5
+
6
+ export { convertClassDeclaration } from "./classes/index.js";
@@ -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
+ };