@tsonic/frontend 0.0.67 → 0.0.68
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/dist/.tsbuildinfo +1 -1
- package/dist/generic-function-values.d.ts.map +1 -1
- package/dist/generic-function-values.js +4 -2
- package/dist/generic-function-values.js.map +1 -1
- package/dist/graph/extraction/imports.d.ts.map +1 -1
- package/dist/graph/extraction/imports.js +5 -1
- package/dist/graph/extraction/imports.js.map +1 -1
- package/dist/ir/binding/binding-factory.d.ts.map +1 -1
- package/dist/ir/binding/binding-factory.js +239 -26
- package/dist/ir/binding/binding-factory.js.map +1 -1
- package/dist/ir/binding/binding-types.d.ts +1 -0
- package/dist/ir/binding/binding-types.d.ts.map +1 -1
- package/dist/ir/binding-resolution.test.js +171 -0
- package/dist/ir/binding-resolution.test.js.map +1 -1
- package/dist/ir/builder/imports.d.ts.map +1 -1
- package/dist/ir/builder/imports.js +13 -1
- package/dist/ir/builder/imports.js.map +1 -1
- package/dist/ir/builder.test.js +1347 -4
- package/dist/ir/builder.test.js.map +1 -1
- package/dist/ir/converters/anonymous-synthesis.d.ts +3 -2
- package/dist/ir/converters/anonymous-synthesis.d.ts.map +1 -1
- package/dist/ir/converters/anonymous-synthesis.js +88 -67
- package/dist/ir/converters/anonymous-synthesis.js.map +1 -1
- package/dist/ir/converters/expressions/access/access-converter.d.ts.map +1 -1
- package/dist/ir/converters/expressions/access/access-converter.js +44 -36
- package/dist/ir/converters/expressions/access/access-converter.js.map +1 -1
- package/dist/ir/converters/expressions/access/binding-resolution.d.ts.map +1 -1
- package/dist/ir/converters/expressions/access/binding-resolution.js.map +1 -1
- package/dist/ir/converters/expressions/access/member-resolution.d.ts.map +1 -1
- package/dist/ir/converters/expressions/access/member-resolution.js +15 -3
- package/dist/ir/converters/expressions/access/member-resolution.js.map +1 -1
- package/dist/ir/converters/expressions/calls/call-converter.d.ts +2 -2
- package/dist/ir/converters/expressions/calls/call-converter.d.ts.map +1 -1
- package/dist/ir/converters/expressions/calls/call-converter.js +108 -4
- package/dist/ir/converters/expressions/calls/call-converter.js.map +1 -1
- package/dist/ir/converters/expressions/calls/new-converter.d.ts +2 -1
- package/dist/ir/converters/expressions/calls/new-converter.d.ts.map +1 -1
- package/dist/ir/converters/expressions/calls/new-converter.js +4 -1
- package/dist/ir/converters/expressions/calls/new-converter.js.map +1 -1
- package/dist/ir/converters/expressions/collections.d.ts.map +1 -1
- package/dist/ir/converters/expressions/collections.js +425 -121
- package/dist/ir/converters/expressions/collections.js.map +1 -1
- package/dist/ir/converters/expressions/dynamic-import.d.ts +6 -0
- package/dist/ir/converters/expressions/dynamic-import.d.ts.map +1 -0
- package/dist/ir/converters/expressions/dynamic-import.js +121 -0
- package/dist/ir/converters/expressions/dynamic-import.js.map +1 -0
- package/dist/ir/converters/expressions/functions.d.ts.map +1 -1
- package/dist/ir/converters/expressions/functions.js +28 -13
- package/dist/ir/converters/expressions/functions.js.map +1 -1
- package/dist/ir/converters/expressions/import-meta.d.ts +9 -0
- package/dist/ir/converters/expressions/import-meta.d.ts.map +1 -0
- package/dist/ir/converters/expressions/import-meta.js +93 -0
- package/dist/ir/converters/expressions/import-meta.js.map +1 -0
- package/dist/ir/converters/expressions/literals.d.ts +2 -1
- package/dist/ir/converters/expressions/literals.d.ts.map +1 -1
- package/dist/ir/converters/expressions/literals.js +73 -0
- package/dist/ir/converters/expressions/literals.js.map +1 -1
- package/dist/ir/converters/flow-narrowing.d.ts.map +1 -1
- package/dist/ir/converters/flow-narrowing.js +100 -0
- package/dist/ir/converters/flow-narrowing.js.map +1 -1
- package/dist/ir/converters/statements/control/loops.d.ts.map +1 -1
- package/dist/ir/converters/statements/control/loops.js +72 -8
- package/dist/ir/converters/statements/control/loops.js.map +1 -1
- package/dist/ir/converters/statements/declarations/variables.d.ts.map +1 -1
- package/dist/ir/converters/statements/declarations/variables.js +22 -6
- package/dist/ir/converters/statements/declarations/variables.js.map +1 -1
- package/dist/ir/expression-converter.d.ts.map +1 -1
- package/dist/ir/expression-converter.js +13 -4
- package/dist/ir/expression-converter.js.map +1 -1
- package/dist/ir/program-context.d.ts +27 -0
- package/dist/ir/program-context.d.ts.map +1 -1
- package/dist/ir/program-context.js +12 -0
- package/dist/ir/program-context.js.map +1 -1
- package/dist/ir/type-system/internal/handle-types.d.ts +1 -0
- package/dist/ir/type-system/internal/handle-types.d.ts.map +1 -1
- package/dist/ir/type-system/internal/type-converter/references.d.ts.map +1 -1
- package/dist/ir/type-system/internal/type-converter/references.js +37 -1
- package/dist/ir/type-system/internal/type-converter/references.js.map +1 -1
- package/dist/ir/type-system/type-system-call-resolution.d.ts +1 -1
- package/dist/ir/type-system/type-system-call-resolution.d.ts.map +1 -1
- package/dist/ir/type-system/type-system-call-resolution.js +158 -26
- package/dist/ir/type-system/type-system-call-resolution.js.map +1 -1
- package/dist/ir/type-system/type-system-inference.d.ts +1 -1
- package/dist/ir/type-system/type-system-inference.d.ts.map +1 -1
- package/dist/ir/type-system/type-system-inference.js +189 -31
- package/dist/ir/type-system/type-system-inference.js.map +1 -1
- package/dist/ir/type-system/type-system-state.d.ts +14 -0
- package/dist/ir/type-system/type-system-state.d.ts.map +1 -1
- package/dist/ir/type-system/type-system-state.js +1 -0
- package/dist/ir/type-system/type-system-state.js.map +1 -1
- package/dist/ir/type-system/type-system.d.ts +5 -1
- package/dist/ir/type-system/type-system.d.ts.map +1 -1
- package/dist/ir/type-system/type-system.js +5 -2
- package/dist/ir/type-system/type-system.js.map +1 -1
- package/dist/ir/types/expressions.d.ts +55 -1
- package/dist/ir/types/expressions.d.ts.map +1 -1
- package/dist/ir/types/index.d.ts +1 -1
- package/dist/ir/types/index.d.ts.map +1 -1
- package/dist/ir/types/index.js.map +1 -1
- package/dist/ir/types/module.d.ts +2 -0
- package/dist/ir/types/module.d.ts.map +1 -1
- package/dist/ir/types/type-ops.d.ts.map +1 -1
- package/dist/ir/types/type-ops.js +1 -0
- package/dist/ir/types/type-ops.js.map +1 -1
- package/dist/ir/types.d.ts +1 -1
- package/dist/ir/types.d.ts.map +1 -1
- package/dist/ir/types.js.map +1 -1
- package/dist/ir/validation/anonymous-type-lowering-pass.d.ts.map +1 -1
- package/dist/ir/validation/anonymous-type-lowering-pass.js +97 -9
- package/dist/ir/validation/anonymous-type-lowering-pass.js.map +1 -1
- package/dist/ir/validation/arrow-return-finalization-pass.js +3 -0
- package/dist/ir/validation/arrow-return-finalization-pass.js.map +1 -1
- package/dist/ir/validation/char-validation-pass.d.ts.map +1 -1
- package/dist/ir/validation/char-validation-pass.js +10 -0
- package/dist/ir/validation/char-validation-pass.js.map +1 -1
- package/dist/ir/validation/numeric-coercion-pass.d.ts.map +1 -1
- package/dist/ir/validation/numeric-coercion-pass.js +6 -0
- package/dist/ir/validation/numeric-coercion-pass.js.map +1 -1
- package/dist/ir/validation/numeric-invariants.test.js +180 -0
- package/dist/ir/validation/numeric-invariants.test.js.map +1 -1
- package/dist/ir/validation/numeric-proof-pass.d.ts.map +1 -1
- package/dist/ir/validation/numeric-proof-pass.js +188 -2
- package/dist/ir/validation/numeric-proof-pass.js.map +1 -1
- package/dist/ir/validation/soundness-gate.d.ts.map +1 -1
- package/dist/ir/validation/soundness-gate.js +29 -10
- package/dist/ir/validation/soundness-gate.js.map +1 -1
- package/dist/ir/validation/soundness-gate.test.js +127 -4
- package/dist/ir/validation/soundness-gate.test.js.map +1 -1
- package/dist/ir/validation/yield-lowering-pass.d.ts.map +1 -1
- package/dist/ir/validation/yield-lowering-pass.js +26 -2
- package/dist/ir/validation/yield-lowering-pass.js.map +1 -1
- package/dist/object-literal-method-runtime.d.ts +15 -0
- package/dist/object-literal-method-runtime.d.ts.map +1 -0
- package/dist/object-literal-method-runtime.js +279 -0
- package/dist/object-literal-method-runtime.js.map +1 -0
- package/dist/program/bindings.test.js +44 -0
- package/dist/program/bindings.test.js.map +1 -1
- package/dist/program/creation.d.ts.map +1 -1
- package/dist/program/creation.js +141 -18
- package/dist/program/creation.js.map +1 -1
- package/dist/program/creation.test.js +312 -2
- package/dist/program/creation.test.js.map +1 -1
- package/dist/program/dependency-graph.d.ts.map +1 -1
- package/dist/program/dependency-graph.js +49 -22
- package/dist/program/dependency-graph.js.map +1 -1
- package/dist/program/dependency-graph.test.d.ts +2 -0
- package/dist/program/dependency-graph.test.d.ts.map +1 -0
- package/dist/program/dependency-graph.test.js +118 -0
- package/dist/program/dependency-graph.test.js.map +1 -0
- package/dist/resolver/dynamic-import.d.ts +33 -0
- package/dist/resolver/dynamic-import.d.ts.map +1 -0
- package/dist/resolver/dynamic-import.js +142 -0
- package/dist/resolver/dynamic-import.js.map +1 -0
- package/dist/resolver/dynamic-import.test.d.ts +2 -0
- package/dist/resolver/dynamic-import.test.d.ts.map +1 -0
- package/dist/resolver/dynamic-import.test.js +150 -0
- package/dist/resolver/dynamic-import.test.js.map +1 -0
- package/dist/resolver/import-resolution.d.ts +2 -0
- package/dist/resolver/import-resolution.d.ts.map +1 -1
- package/dist/resolver/import-resolution.js +20 -3
- package/dist/resolver/import-resolution.js.map +1 -1
- package/dist/resolver/source-package-resolution.d.ts +11 -0
- package/dist/resolver/source-package-resolution.d.ts.map +1 -0
- package/dist/resolver/source-package-resolution.js +188 -0
- package/dist/resolver/source-package-resolution.js.map +1 -0
- package/dist/resolver/source-package-resolution.test.d.ts +2 -0
- package/dist/resolver/source-package-resolution.test.d.ts.map +1 -0
- package/dist/resolver/source-package-resolution.test.js +77 -0
- package/dist/resolver/source-package-resolution.test.js.map +1 -0
- package/dist/resolver/types.d.ts +1 -0
- package/dist/resolver/types.d.ts.map +1 -1
- package/dist/resolver.test.js +83 -0
- package/dist/resolver.test.js.map +1 -1
- package/dist/surface/profiles.d.ts +1 -0
- package/dist/surface/profiles.d.ts.map +1 -1
- package/dist/surface/profiles.js +4 -2
- package/dist/surface/profiles.js.map +1 -1
- package/dist/surface/profiles.test.js +10 -0
- package/dist/surface/profiles.test.js.map +1 -1
- package/dist/types/module.d.ts +1 -1
- package/dist/types/module.d.ts.map +1 -1
- package/dist/validation/features.d.ts +1 -1
- package/dist/validation/features.d.ts.map +1 -1
- package/dist/validation/features.js +37 -6
- package/dist/validation/features.js.map +1 -1
- package/dist/validation/features.test.js +137 -23
- package/dist/validation/features.test.js.map +1 -1
- package/dist/validation/imports.d.ts.map +1 -1
- package/dist/validation/imports.js +2 -8
- package/dist/validation/imports.js.map +1 -1
- package/dist/validation/imports.test.js +6 -9
- package/dist/validation/imports.test.js.map +1 -1
- package/dist/validation/static-safety.d.ts.map +1 -1
- package/dist/validation/static-safety.js +118 -67
- package/dist/validation/static-safety.js.map +1 -1
- package/dist/validator.maximus.test.js +225 -33
- package/dist/validator.maximus.test.js.map +1 -1
- package/dist/validator.test.js +87 -6
- package/dist/validator.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,11 +2,14 @@
|
|
|
2
2
|
* Collection expression converters (arrays and objects)
|
|
3
3
|
*/
|
|
4
4
|
import * as ts from "typescript";
|
|
5
|
-
import { typesEqual } from "../../types/ir-substitution.js";
|
|
5
|
+
import { containsTypeParameter, typesEqual, } from "../../types/ir-substitution.js";
|
|
6
6
|
import { getSourceSpan, getContextualType } from "./helpers.js";
|
|
7
7
|
import { convertExpression } from "../../expression-converter.js";
|
|
8
|
-
import { checkSynthesisEligibility
|
|
8
|
+
import { checkSynthesisEligibility } from "../anonymous-synthesis.js";
|
|
9
9
|
import { createDiagnostic } from "../../../types/diagnostic.js";
|
|
10
|
+
import { convertAccessorProperty } from "../statements/declarations/classes/properties.js";
|
|
11
|
+
import { convertBindingName } from "../../syntax/binding-patterns.js";
|
|
12
|
+
import { createObjectLiteralMethodArgumentPrelude } from "../../../object-literal-method-runtime.js";
|
|
10
13
|
/**
|
|
11
14
|
* Compute the element type for an array literal from its elements' types.
|
|
12
15
|
*
|
|
@@ -19,9 +22,78 @@ import { createDiagnostic } from "../../../types/diagnostic.js";
|
|
|
19
22
|
* 6. Mixed or complex → fall back to TS inference
|
|
20
23
|
*/
|
|
21
24
|
const computeArrayElementType = (elements, fallbackType) => {
|
|
25
|
+
const mergeElementTypes = (types) => {
|
|
26
|
+
if (types.length === 0)
|
|
27
|
+
return undefined;
|
|
28
|
+
const first = types[0];
|
|
29
|
+
if (first && types.every((t) => typesEqual(t, first))) {
|
|
30
|
+
return first;
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
kind: "unionType",
|
|
34
|
+
types,
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
const extractSpreadElementTypes = (type) => {
|
|
38
|
+
if (!type)
|
|
39
|
+
return undefined;
|
|
40
|
+
if (type.kind === "arrayType") {
|
|
41
|
+
return [type.elementType];
|
|
42
|
+
}
|
|
43
|
+
if (type.kind === "tupleType") {
|
|
44
|
+
return type.elementTypes.filter((element) => element !== undefined);
|
|
45
|
+
}
|
|
46
|
+
if (type.kind === "unionType") {
|
|
47
|
+
const members = [];
|
|
48
|
+
for (const member of type.types) {
|
|
49
|
+
const extracted = extractSpreadElementTypes(member);
|
|
50
|
+
if (!extracted)
|
|
51
|
+
return undefined;
|
|
52
|
+
members.push(...extracted);
|
|
53
|
+
}
|
|
54
|
+
return members;
|
|
55
|
+
}
|
|
56
|
+
if (type.kind === "referenceType" &&
|
|
57
|
+
type.typeArguments &&
|
|
58
|
+
type.typeArguments.length > 0) {
|
|
59
|
+
const simpleName = type.name.split(".").pop() ?? type.name;
|
|
60
|
+
switch (simpleName) {
|
|
61
|
+
case "Array":
|
|
62
|
+
case "ReadonlyArray":
|
|
63
|
+
case "Iterable":
|
|
64
|
+
case "IterableIterator":
|
|
65
|
+
case "Iterator":
|
|
66
|
+
case "AsyncIterable":
|
|
67
|
+
case "AsyncIterableIterator":
|
|
68
|
+
case "Generator":
|
|
69
|
+
case "AsyncGenerator":
|
|
70
|
+
case "Set":
|
|
71
|
+
case "ReadonlySet":
|
|
72
|
+
case "JSArray":
|
|
73
|
+
case "IEnumerable":
|
|
74
|
+
case "IReadOnlyList":
|
|
75
|
+
case "List":
|
|
76
|
+
return type.typeArguments[0] ? [type.typeArguments[0]] : undefined;
|
|
77
|
+
case "Map":
|
|
78
|
+
case "ReadonlyMap":
|
|
79
|
+
return type.typeArguments[0] && type.typeArguments[1]
|
|
80
|
+
? [
|
|
81
|
+
{
|
|
82
|
+
kind: "tupleType",
|
|
83
|
+
elementTypes: [type.typeArguments[0], type.typeArguments[1]],
|
|
84
|
+
},
|
|
85
|
+
]
|
|
86
|
+
: undefined;
|
|
87
|
+
default:
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return undefined;
|
|
92
|
+
};
|
|
22
93
|
// Filter out holes and spreads for type analysis
|
|
23
94
|
const regularElements = elements.filter((e) => e !== undefined && e.kind !== "spread");
|
|
24
|
-
|
|
95
|
+
const spreadElements = elements.filter((e) => e !== undefined && e.kind === "spread");
|
|
96
|
+
if (regularElements.length === 0 && spreadElements.length === 0) {
|
|
25
97
|
// Empty array - use fallback
|
|
26
98
|
return fallbackType;
|
|
27
99
|
}
|
|
@@ -59,8 +131,11 @@ const computeArrayElementType = (elements, fallbackType) => {
|
|
|
59
131
|
allBooleanLiterals = false;
|
|
60
132
|
}
|
|
61
133
|
}
|
|
134
|
+
const hasOnlyRegularElements = regularElements.length > 0 && spreadElements.length === 0;
|
|
62
135
|
// All numeric literals - determine widest type
|
|
63
|
-
if (
|
|
136
|
+
if (hasOnlyRegularElements &&
|
|
137
|
+
allNumericLiterals &&
|
|
138
|
+
numericIntents.length > 0) {
|
|
64
139
|
// Any Double → number (emits as "double" in C#)
|
|
65
140
|
if (numericIntents.includes("Double") ||
|
|
66
141
|
numericIntents.includes("Single")) {
|
|
@@ -74,11 +149,11 @@ const computeArrayElementType = (elements, fallbackType) => {
|
|
|
74
149
|
return { kind: "primitiveType", name: "int" };
|
|
75
150
|
}
|
|
76
151
|
// All string literals
|
|
77
|
-
if (allStringLiterals) {
|
|
152
|
+
if (hasOnlyRegularElements && allStringLiterals) {
|
|
78
153
|
return { kind: "primitiveType", name: "string" };
|
|
79
154
|
}
|
|
80
155
|
// All boolean literals
|
|
81
|
-
if (allBooleanLiterals) {
|
|
156
|
+
if (hasOnlyRegularElements && allBooleanLiterals) {
|
|
82
157
|
return { kind: "primitiveType", name: "boolean" };
|
|
83
158
|
}
|
|
84
159
|
// Mixed or complex - fall back to TS inference
|
|
@@ -93,9 +168,16 @@ const computeArrayElementType = (elements, fallbackType) => {
|
|
|
93
168
|
}
|
|
94
169
|
knownTypes.push(t);
|
|
95
170
|
}
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
171
|
+
for (const spread of spreadElements) {
|
|
172
|
+
const spreadTypes = extractSpreadElementTypes(spread.expression.inferredType);
|
|
173
|
+
if (!spreadTypes) {
|
|
174
|
+
return fallbackType;
|
|
175
|
+
}
|
|
176
|
+
knownTypes.push(...spreadTypes);
|
|
177
|
+
}
|
|
178
|
+
const merged = mergeElementTypes(knownTypes);
|
|
179
|
+
if (merged) {
|
|
180
|
+
return merged;
|
|
99
181
|
}
|
|
100
182
|
return fallbackType;
|
|
101
183
|
};
|
|
@@ -113,8 +195,11 @@ const computeArrayElementType = (elements, fallbackType) => {
|
|
|
113
195
|
* Pass `undefined` explicitly when no contextual type exists.
|
|
114
196
|
*/
|
|
115
197
|
export const convertArrayLiteral = (node, ctx, expectedType) => {
|
|
198
|
+
const contextualArrayType = expectedType?.kind === "arrayType" && !containsTypeParameter(expectedType)
|
|
199
|
+
? expectedType
|
|
200
|
+
: undefined;
|
|
116
201
|
// Determine element expected type from array expected type
|
|
117
|
-
const expectedElementType =
|
|
202
|
+
const expectedElementType = contextualArrayType?.elementType;
|
|
118
203
|
// Convert all elements, passing expected element type for contextual typing
|
|
119
204
|
const elements = node.elements.map((elem) => {
|
|
120
205
|
if (ts.isOmittedExpression(elem)) {
|
|
@@ -136,8 +221,8 @@ export const convertArrayLiteral = (node, ctx, expectedType) => {
|
|
|
136
221
|
// 1. Expected type from context (e.g., LHS annotation, parameter type)
|
|
137
222
|
// 2. Literal-form inference (derive from element types)
|
|
138
223
|
// 3. Default: number[] (double[]) for ergonomics
|
|
139
|
-
const inferredType =
|
|
140
|
-
?
|
|
224
|
+
const inferredType = contextualArrayType
|
|
225
|
+
? contextualArrayType
|
|
141
226
|
: (() => {
|
|
142
227
|
// No expected type - derive from element types
|
|
143
228
|
const elementType = computeArrayElementType(elements, undefined);
|
|
@@ -191,6 +276,249 @@ const getPropertyExpectedType = (propName, expectedType, ctx) => {
|
|
|
191
276
|
}
|
|
192
277
|
return undefined;
|
|
193
278
|
};
|
|
279
|
+
const unwrapDeterministicKeyExpression = (expr) => {
|
|
280
|
+
let current = expr;
|
|
281
|
+
for (;;) {
|
|
282
|
+
if (ts.isParenthesizedExpression(current)) {
|
|
283
|
+
current = current.expression;
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
if (ts.isAsExpression(current) ||
|
|
287
|
+
ts.isTypeAssertionExpression(current) ||
|
|
288
|
+
ts.isSatisfiesExpression(current)) {
|
|
289
|
+
current = current.expression;
|
|
290
|
+
continue;
|
|
291
|
+
}
|
|
292
|
+
return current;
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
const tryResolveDeterministicObjectKeyNameFromSyntax = (expr, ctx, seenSymbols = new Set()) => {
|
|
296
|
+
const current = unwrapDeterministicKeyExpression(expr);
|
|
297
|
+
if (ts.isStringLiteral(current) ||
|
|
298
|
+
ts.isNoSubstitutionTemplateLiteral(current) ||
|
|
299
|
+
ts.isNumericLiteral(current)) {
|
|
300
|
+
return String(current.text);
|
|
301
|
+
}
|
|
302
|
+
if (!ts.isIdentifier(current)) {
|
|
303
|
+
return undefined;
|
|
304
|
+
}
|
|
305
|
+
const symbol = ctx.checker.getSymbolAtLocation(current);
|
|
306
|
+
if (!symbol || seenSymbols.has(symbol)) {
|
|
307
|
+
return undefined;
|
|
308
|
+
}
|
|
309
|
+
seenSymbols.add(symbol);
|
|
310
|
+
const visitDeclarations = (target) => {
|
|
311
|
+
for (const decl of target.getDeclarations() ?? []) {
|
|
312
|
+
if (ts.isVariableDeclaration(decl) &&
|
|
313
|
+
decl.initializer &&
|
|
314
|
+
ts.isVariableDeclarationList(decl.parent) &&
|
|
315
|
+
(decl.parent.flags & ts.NodeFlags.Const) !== 0) {
|
|
316
|
+
const resolved = tryResolveDeterministicObjectKeyNameFromSyntax(decl.initializer, ctx, seenSymbols);
|
|
317
|
+
if (resolved !== undefined)
|
|
318
|
+
return resolved;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return undefined;
|
|
322
|
+
};
|
|
323
|
+
const direct = visitDeclarations(symbol);
|
|
324
|
+
if (direct !== undefined)
|
|
325
|
+
return direct;
|
|
326
|
+
if ((symbol.flags & ts.SymbolFlags.Alias) !== 0) {
|
|
327
|
+
const aliased = ctx.checker.getAliasedSymbol(symbol);
|
|
328
|
+
if (!seenSymbols.has(aliased)) {
|
|
329
|
+
seenSymbols.add(aliased);
|
|
330
|
+
return visitDeclarations(aliased);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return undefined;
|
|
334
|
+
};
|
|
335
|
+
const resolveObjectLiteralMemberKey = (name, ctx) => {
|
|
336
|
+
if (ts.isIdentifier(name) ||
|
|
337
|
+
ts.isStringLiteral(name) ||
|
|
338
|
+
ts.isNoSubstitutionTemplateLiteral(name) ||
|
|
339
|
+
ts.isNumericLiteral(name)) {
|
|
340
|
+
const keyName = String(name.text);
|
|
341
|
+
return { key: keyName, keyName };
|
|
342
|
+
}
|
|
343
|
+
if (!ts.isComputedPropertyName(name)) {
|
|
344
|
+
return { key: "", keyName: undefined };
|
|
345
|
+
}
|
|
346
|
+
const keyName = tryResolveDeterministicObjectKeyNameFromSyntax(name.expression, ctx);
|
|
347
|
+
const computedKey = convertExpression(unwrapDeterministicKeyExpression(name.expression), ctx, undefined);
|
|
348
|
+
return { key: keyName ?? computedKey, keyName };
|
|
349
|
+
};
|
|
350
|
+
const methodUsesObjectLiteralThis = (method) => {
|
|
351
|
+
let found = false;
|
|
352
|
+
const visit = (current) => {
|
|
353
|
+
if (found)
|
|
354
|
+
return;
|
|
355
|
+
if (current.kind === ts.SyntaxKind.ThisKeyword) {
|
|
356
|
+
found = true;
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
if (ts.isFunctionExpression(current) ||
|
|
360
|
+
ts.isFunctionDeclaration(current) ||
|
|
361
|
+
ts.isMethodDeclaration(current) ||
|
|
362
|
+
ts.isGetAccessorDeclaration(current) ||
|
|
363
|
+
ts.isSetAccessorDeclaration(current)) {
|
|
364
|
+
if (current !== method) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
ts.forEachChild(current, visit);
|
|
369
|
+
};
|
|
370
|
+
if (method.body) {
|
|
371
|
+
visit(method.body);
|
|
372
|
+
}
|
|
373
|
+
return found;
|
|
374
|
+
};
|
|
375
|
+
const isNullishPrimitive = (type) => type.kind === "primitiveType" &&
|
|
376
|
+
(type.name === "null" || type.name === "undefined");
|
|
377
|
+
const normalizeExpectedFunctionType = (expectedType, ctx) => {
|
|
378
|
+
if (!expectedType)
|
|
379
|
+
return undefined;
|
|
380
|
+
if (expectedType.kind === "functionType")
|
|
381
|
+
return expectedType;
|
|
382
|
+
const delegated = ctx.typeSystem.delegateToFunctionType(expectedType);
|
|
383
|
+
if (delegated)
|
|
384
|
+
return delegated;
|
|
385
|
+
if (expectedType.kind !== "unionType")
|
|
386
|
+
return undefined;
|
|
387
|
+
const candidates = expectedType.types
|
|
388
|
+
.filter((member) => !!member && !isNullishPrimitive(member))
|
|
389
|
+
.map((member) => member.kind === "functionType"
|
|
390
|
+
? member
|
|
391
|
+
: ctx.typeSystem.delegateToFunctionType(member))
|
|
392
|
+
.filter((member) => member !== undefined);
|
|
393
|
+
return candidates.length === 1 ? candidates[0] : undefined;
|
|
394
|
+
};
|
|
395
|
+
const getExpectedFunctionParameterTypes = (expectedType, ctx) => {
|
|
396
|
+
const fnType = normalizeExpectedFunctionType(expectedType, ctx);
|
|
397
|
+
return fnType?.parameters.map((param) => param.type);
|
|
398
|
+
};
|
|
399
|
+
const convertObjectLiteralMethodParameters = (parameters, ctx, expectedType) => {
|
|
400
|
+
const expectedParamTypes = getExpectedFunctionParameterTypes(expectedType, ctx);
|
|
401
|
+
return parameters.map((param, index) => {
|
|
402
|
+
const explicitType = param.type
|
|
403
|
+
? ctx.typeSystem.typeFromSyntax(ctx.binding.captureTypeSyntax(param.type))
|
|
404
|
+
: undefined;
|
|
405
|
+
const paramType = explicitType ?? expectedParamTypes?.[index];
|
|
406
|
+
return {
|
|
407
|
+
kind: "parameter",
|
|
408
|
+
pattern: convertBindingName(param.name, ctx),
|
|
409
|
+
type: paramType,
|
|
410
|
+
initializer: param.initializer
|
|
411
|
+
? convertExpression(param.initializer, ctx, paramType)
|
|
412
|
+
: undefined,
|
|
413
|
+
isOptional: !!param.questionToken,
|
|
414
|
+
isRest: !!param.dotDotDotToken,
|
|
415
|
+
passing: "value",
|
|
416
|
+
};
|
|
417
|
+
});
|
|
418
|
+
};
|
|
419
|
+
const buildObjectLiteralMethodFunctionType = (method, ctx, expectedType) => {
|
|
420
|
+
const expectedFnType = normalizeExpectedFunctionType(expectedType, ctx);
|
|
421
|
+
const parameters = convertObjectLiteralMethodParameters(method.parameters, ctx, expectedFnType ?? expectedType);
|
|
422
|
+
const declaredReturnType = method.type
|
|
423
|
+
? ctx.typeSystem.typeFromSyntax(ctx.binding.captureTypeSyntax(method.type))
|
|
424
|
+
: undefined;
|
|
425
|
+
return {
|
|
426
|
+
kind: "functionType",
|
|
427
|
+
parameters,
|
|
428
|
+
returnType: declaredReturnType ??
|
|
429
|
+
expectedFnType?.returnType ?? { kind: "unknownType" },
|
|
430
|
+
};
|
|
431
|
+
};
|
|
432
|
+
const getSynthesizedPropertyType = (expr, widenNumericLiterals) => {
|
|
433
|
+
if (widenNumericLiterals &&
|
|
434
|
+
expr.kind === "literal" &&
|
|
435
|
+
typeof expr.value === "number") {
|
|
436
|
+
return { kind: "primitiveType", name: "number" };
|
|
437
|
+
}
|
|
438
|
+
return expr.inferredType;
|
|
439
|
+
};
|
|
440
|
+
const getProvisionalAccessorPropertyType = (getter, setter, expectedType, ctx) => {
|
|
441
|
+
const getterType = getter?.type
|
|
442
|
+
? ctx.typeSystem.typeFromSyntax(ctx.binding.captureTypeSyntax(getter.type))
|
|
443
|
+
: undefined;
|
|
444
|
+
const setterValueParam = setter?.parameters[0];
|
|
445
|
+
const setterType = setterValueParam?.type !== undefined
|
|
446
|
+
? ctx.typeSystem.typeFromSyntax(ctx.binding.captureTypeSyntax(setterValueParam.type))
|
|
447
|
+
: undefined;
|
|
448
|
+
return getterType ?? setterType ?? expectedType;
|
|
449
|
+
};
|
|
450
|
+
const collectSynthesizedObjectMembers = (properties, pendingMethods, pendingAccessors, widenNumericLiterals) => {
|
|
451
|
+
const synthesizedMembers = [];
|
|
452
|
+
for (const prop of properties) {
|
|
453
|
+
if (prop.kind === "property") {
|
|
454
|
+
const keyName = typeof prop.key === "string"
|
|
455
|
+
? prop.key
|
|
456
|
+
: prop.key.kind === "literal" && typeof prop.key.value === "string"
|
|
457
|
+
? prop.key.value
|
|
458
|
+
: undefined;
|
|
459
|
+
if (!keyName) {
|
|
460
|
+
return {
|
|
461
|
+
ok: false,
|
|
462
|
+
failureReason: "Only identifier and computed string-literal keys are supported",
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
const propType = getSynthesizedPropertyType(prop.value, widenNumericLiterals);
|
|
466
|
+
if (!propType ||
|
|
467
|
+
propType.kind === "unknownType" ||
|
|
468
|
+
propType.kind === "anyType") {
|
|
469
|
+
return {
|
|
470
|
+
ok: false,
|
|
471
|
+
failureReason: `Property '${keyName}' type cannot be recovered deterministically`,
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
synthesizedMembers.push({
|
|
475
|
+
kind: "propertySignature",
|
|
476
|
+
name: keyName,
|
|
477
|
+
type: propType,
|
|
478
|
+
isOptional: false,
|
|
479
|
+
isReadonly: false,
|
|
480
|
+
});
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
const spreadType = prop.expression.inferredType;
|
|
484
|
+
if (spreadType?.kind !== "objectType") {
|
|
485
|
+
return {
|
|
486
|
+
ok: false,
|
|
487
|
+
failureReason: "Spread sources must have a deterministically known object literal shape",
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
for (const member of spreadType.members) {
|
|
491
|
+
if (member.kind === "propertySignature") {
|
|
492
|
+
synthesizedMembers.push(member);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
for (const method of pendingMethods) {
|
|
497
|
+
synthesizedMembers.push({
|
|
498
|
+
kind: "propertySignature",
|
|
499
|
+
name: method.keyName,
|
|
500
|
+
type: method.functionType,
|
|
501
|
+
isOptional: false,
|
|
502
|
+
isReadonly: false,
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
for (const accessor of pendingAccessors) {
|
|
506
|
+
if (!accessor.propertyType) {
|
|
507
|
+
return {
|
|
508
|
+
ok: false,
|
|
509
|
+
failureReason: `Accessor '${accessor.memberName}' type cannot be recovered deterministically`,
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
synthesizedMembers.push({
|
|
513
|
+
kind: "propertySignature",
|
|
514
|
+
name: accessor.memberName,
|
|
515
|
+
type: accessor.propertyType,
|
|
516
|
+
isOptional: false,
|
|
517
|
+
isReadonly: false,
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
return { ok: true, members: synthesizedMembers };
|
|
521
|
+
};
|
|
194
522
|
/**
|
|
195
523
|
* Convert object literal expression
|
|
196
524
|
*
|
|
@@ -201,6 +529,9 @@ const getPropertyExpectedType = (propName, expectedType, ctx) => {
|
|
|
201
529
|
*/
|
|
202
530
|
export const convertObjectLiteral = (node, ctx, expectedType) => {
|
|
203
531
|
const properties = [];
|
|
532
|
+
const behaviorMembers = [];
|
|
533
|
+
const pendingMethods = [];
|
|
534
|
+
const accessorGroups = new Map();
|
|
204
535
|
// Contextual type priority:
|
|
205
536
|
// 1) expectedType threaded from the parent converter (return, assignment, parameter, etc.)
|
|
206
537
|
// 2) AST-based contextual typing from explicit TypeNodes (getContextualType)
|
|
@@ -242,27 +573,18 @@ export const convertObjectLiteral = (node, ctx, expectedType) => {
|
|
|
242
573
|
ts.isShorthandPropertyAssignment(p));
|
|
243
574
|
const shouldLowerToDictionary = isObjectLikeContext && isPlainObjectLiteralAst;
|
|
244
575
|
const dictionaryValueExpectedType = { kind: "unknownType" };
|
|
576
|
+
const getObjectLiteralPropertyExpectedType = (keyName) => keyName
|
|
577
|
+
? (getPropertyExpectedType(keyName, expectedType, ctx) ??
|
|
578
|
+
(shouldLowerToDictionary ? dictionaryValueExpectedType : undefined))
|
|
579
|
+
: shouldLowerToDictionary
|
|
580
|
+
? dictionaryValueExpectedType
|
|
581
|
+
: undefined;
|
|
245
582
|
// Track if we have any spreads (needed for emitter IIFE lowering)
|
|
246
583
|
let hasSpreads = false;
|
|
247
584
|
node.properties.forEach((prop) => {
|
|
248
585
|
if (ts.isPropertyAssignment(prop)) {
|
|
249
|
-
const keyName =
|
|
250
|
-
|
|
251
|
-
: ts.isStringLiteral(prop.name)
|
|
252
|
-
? prop.name.text
|
|
253
|
-
: undefined;
|
|
254
|
-
const key = ts.isComputedPropertyName(prop.name)
|
|
255
|
-
? convertExpression(prop.name.expression, ctx, undefined)
|
|
256
|
-
: ts.isIdentifier(prop.name)
|
|
257
|
-
? prop.name.text
|
|
258
|
-
: String(prop.name.text);
|
|
259
|
-
// Look up property expected type from parent expected type
|
|
260
|
-
const propExpectedType = keyName
|
|
261
|
-
? (getPropertyExpectedType(keyName, expectedType, ctx) ??
|
|
262
|
-
(shouldLowerToDictionary ? dictionaryValueExpectedType : undefined))
|
|
263
|
-
: shouldLowerToDictionary
|
|
264
|
-
? dictionaryValueExpectedType
|
|
265
|
-
: undefined;
|
|
586
|
+
const { key, keyName } = resolveObjectLiteralMemberKey(prop.name, ctx);
|
|
587
|
+
const propExpectedType = getObjectLiteralPropertyExpectedType(keyName);
|
|
266
588
|
properties.push({
|
|
267
589
|
kind: "property",
|
|
268
590
|
key,
|
|
@@ -305,32 +627,44 @@ export const convertObjectLiteral = (node, ctx, expectedType) => {
|
|
|
305
627
|
});
|
|
306
628
|
}
|
|
307
629
|
else if (ts.isMethodDeclaration(prop)) {
|
|
308
|
-
const keyName =
|
|
309
|
-
|
|
310
|
-
:
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
: ts.isIdentifier(prop.name)
|
|
316
|
-
? prop.name.text
|
|
317
|
-
: String(prop.name.text);
|
|
318
|
-
const propExpectedType = keyName
|
|
319
|
-
? (getPropertyExpectedType(keyName, expectedType, ctx) ??
|
|
320
|
-
(shouldLowerToDictionary ? dictionaryValueExpectedType : undefined))
|
|
321
|
-
: shouldLowerToDictionary
|
|
322
|
-
? dictionaryValueExpectedType
|
|
323
|
-
: undefined;
|
|
324
|
-
const methodModifiers = prop.modifiers?.filter(ts.isModifier);
|
|
325
|
-
const methodAsFunctionExpr = ts.setTextRange(ts.factory.createFunctionExpression(methodModifiers, prop.asteriskToken, undefined, prop.typeParameters, prop.parameters, prop.type, prop.body ?? ts.factory.createBlock([], true)), prop);
|
|
326
|
-
properties.push({
|
|
327
|
-
kind: "property",
|
|
630
|
+
const { key, keyName } = resolveObjectLiteralMemberKey(prop.name, ctx);
|
|
631
|
+
if (!keyName) {
|
|
632
|
+
ctx.diagnostics.push(createDiagnostic("TSN7403", "error", "Object literal cannot be synthesized: computed method key is not a deterministically known string/number literal", getSourceSpan(prop), "Use an identifier, string literal key, or explicit type annotation."));
|
|
633
|
+
return;
|
|
634
|
+
}
|
|
635
|
+
const propExpectedType = getObjectLiteralPropertyExpectedType(keyName);
|
|
636
|
+
pendingMethods.push({
|
|
328
637
|
key,
|
|
329
|
-
|
|
330
|
-
|
|
638
|
+
keyName,
|
|
639
|
+
node: prop,
|
|
640
|
+
propExpectedType,
|
|
641
|
+
capturesObjectLiteralThis: methodUsesObjectLiteralThis(prop),
|
|
642
|
+
functionType: buildObjectLiteralMethodFunctionType(prop, ctx, propExpectedType),
|
|
331
643
|
});
|
|
332
644
|
}
|
|
645
|
+
else if (ts.isGetAccessorDeclaration(prop) ||
|
|
646
|
+
ts.isSetAccessorDeclaration(prop)) {
|
|
647
|
+
const { keyName: memberName } = resolveObjectLiteralMemberKey(prop.name, ctx);
|
|
648
|
+
if (!memberName) {
|
|
649
|
+
ctx.diagnostics.push(createDiagnostic("TSN7403", "error", "Object literal cannot be synthesized: computed accessor key is not a deterministically known string/number literal", getSourceSpan(prop), "Use an identifier, string literal key, or explicit type annotation."));
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
const existing = accessorGroups.get(memberName) ?? {};
|
|
653
|
+
if (ts.isGetAccessorDeclaration(prop)) {
|
|
654
|
+
existing.getter = prop;
|
|
655
|
+
}
|
|
656
|
+
else {
|
|
657
|
+
existing.setter = prop;
|
|
658
|
+
}
|
|
659
|
+
accessorGroups.set(memberName, existing);
|
|
660
|
+
}
|
|
333
661
|
});
|
|
662
|
+
const pendingAccessors = Array.from(accessorGroups.entries()).map(([memberName, group]) => ({
|
|
663
|
+
memberName,
|
|
664
|
+
getter: group.getter,
|
|
665
|
+
setter: group.setter,
|
|
666
|
+
propertyType: getProvisionalAccessorPropertyType(group.getter, group.setter, getObjectLiteralPropertyExpectedType(memberName), ctx),
|
|
667
|
+
}));
|
|
334
668
|
let contextualType = contextualCandidate;
|
|
335
669
|
if (isObjectLikeContext) {
|
|
336
670
|
contextualType = shouldLowerToDictionary
|
|
@@ -349,90 +683,60 @@ export const convertObjectLiteral = (node, ctx, expectedType) => {
|
|
|
349
683
|
ctx.diagnostics.push(createDiagnostic("TSN7403", "error", `Object literal cannot be synthesized: ${eligibility.reason}`, getSourceSpan(node), "Use an explicit type annotation, or restructure to use only identifier keys, string literal keys, spread identifiers with type annotations, and function-valued properties."));
|
|
350
684
|
}
|
|
351
685
|
else {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
let canSynthesize = true;
|
|
355
|
-
let synthesisFailureReason;
|
|
356
|
-
for (const prop of properties) {
|
|
357
|
-
if (prop.kind === "property") {
|
|
358
|
-
// Get property name (identifier or computed string-literal keys).
|
|
359
|
-
const keyName = typeof prop.key === "string"
|
|
360
|
-
? prop.key
|
|
361
|
-
: prop.key.kind === "literal" &&
|
|
362
|
-
typeof prop.key.value === "string"
|
|
363
|
-
? prop.key.value
|
|
364
|
-
: undefined;
|
|
365
|
-
if (!keyName) {
|
|
366
|
-
canSynthesize = false;
|
|
367
|
-
synthesisFailureReason =
|
|
368
|
-
"Only identifier and computed string-literal keys are supported";
|
|
369
|
-
break;
|
|
370
|
-
}
|
|
371
|
-
// Get type from converted expression's inferredType
|
|
372
|
-
const propType = prop.value.inferredType;
|
|
373
|
-
if (!propType ||
|
|
374
|
-
propType.kind === "unknownType" ||
|
|
375
|
-
propType.kind === "anyType") {
|
|
376
|
-
// Cannot synthesize if property type is unknown/any
|
|
377
|
-
canSynthesize = false;
|
|
378
|
-
synthesisFailureReason = `Property '${keyName}' type cannot be recovered deterministically`;
|
|
379
|
-
break;
|
|
380
|
-
}
|
|
381
|
-
propInfos.push({
|
|
382
|
-
name: keyName,
|
|
383
|
-
type: propType,
|
|
384
|
-
optional: false,
|
|
385
|
-
readonly: false,
|
|
386
|
-
});
|
|
387
|
-
}
|
|
388
|
-
else if (prop.kind === "spread") {
|
|
389
|
-
// For spreads, merge properties from the spread source's objectType
|
|
390
|
-
const spreadType = prop.expression.inferredType;
|
|
391
|
-
if (spreadType?.kind === "objectType") {
|
|
392
|
-
for (const member of spreadType.members) {
|
|
393
|
-
if (member.kind === "propertySignature") {
|
|
394
|
-
propInfos.push({
|
|
395
|
-
name: member.name,
|
|
396
|
-
type: member.type,
|
|
397
|
-
optional: member.isOptional,
|
|
398
|
-
readonly: member.isReadonly,
|
|
399
|
-
});
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
else {
|
|
404
|
-
canSynthesize = false;
|
|
405
|
-
synthesisFailureReason =
|
|
406
|
-
"Spread sources must have a deterministically known object literal shape";
|
|
407
|
-
break;
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
if (canSynthesize) {
|
|
412
|
-
// DETERMINISTIC: synthesize an objectType shape from the AST, then allow the
|
|
413
|
-
// anonymous-type-lowering pass to generate a nominal type (class) for emission.
|
|
686
|
+
const synthesized = collectSynthesizedObjectMembers(properties, pendingMethods, pendingAccessors, pendingAccessors.length > 0);
|
|
687
|
+
if (synthesized.ok && synthesized.members) {
|
|
414
688
|
contextualType = {
|
|
415
689
|
kind: "objectType",
|
|
416
|
-
members:
|
|
417
|
-
kind: "propertySignature",
|
|
418
|
-
name: p.name,
|
|
419
|
-
type: p.type,
|
|
420
|
-
isOptional: p.optional,
|
|
421
|
-
isReadonly: p.readonly,
|
|
422
|
-
})),
|
|
690
|
+
members: synthesized.members,
|
|
423
691
|
};
|
|
424
692
|
}
|
|
425
693
|
else {
|
|
426
|
-
ctx.diagnostics.push(createDiagnostic("TSN7403", "error", `Object literal cannot be synthesized: ${
|
|
694
|
+
ctx.diagnostics.push(createDiagnostic("TSN7403", "error", `Object literal cannot be synthesized: ${synthesized.failureReason ?? "not supported in this context"}`, getSourceSpan(node), "Use an explicit type annotation, or restructure to use only identifier keys, string literal keys, spread identifiers with type annotations, and function-valued properties."));
|
|
427
695
|
}
|
|
428
696
|
}
|
|
429
697
|
}
|
|
698
|
+
const objectLiteralThisType = contextualType && contextualType.kind !== "dictionaryType"
|
|
699
|
+
? contextualType
|
|
700
|
+
: undefined;
|
|
701
|
+
const objectBehaviorContext = objectLiteralThisType
|
|
702
|
+
? { ...ctx, objectLiteralThisType }
|
|
703
|
+
: ctx;
|
|
704
|
+
for (const pendingMethod of pendingMethods) {
|
|
705
|
+
const methodPrelude = createObjectLiteralMethodArgumentPrelude(pendingMethod.node);
|
|
706
|
+
const methodBody = pendingMethod.node.body
|
|
707
|
+
? methodPrelude.length > 0
|
|
708
|
+
? ts.factory.updateBlock(pendingMethod.node.body, [
|
|
709
|
+
...methodPrelude,
|
|
710
|
+
...pendingMethod.node.body.statements,
|
|
711
|
+
])
|
|
712
|
+
: pendingMethod.node.body
|
|
713
|
+
: ts.factory.createBlock(methodPrelude, true);
|
|
714
|
+
const methodModifiers = pendingMethod.node.modifiers?.filter(ts.isModifier);
|
|
715
|
+
const methodAsFunctionExpr = ts.setTextRange(ts.factory.createFunctionExpression(methodModifiers, pendingMethod.node.asteriskToken, undefined, pendingMethod.node.typeParameters, pendingMethod.node.parameters, pendingMethod.node.type, methodBody), pendingMethod.node);
|
|
716
|
+
const convertedValue = convertExpression(methodAsFunctionExpr, objectBehaviorContext, pendingMethod.propExpectedType);
|
|
717
|
+
properties.push({
|
|
718
|
+
kind: "property",
|
|
719
|
+
key: pendingMethod.key,
|
|
720
|
+
value: convertedValue.kind === "functionExpression" &&
|
|
721
|
+
pendingMethod.capturesObjectLiteralThis
|
|
722
|
+
? {
|
|
723
|
+
...convertedValue,
|
|
724
|
+
capturesObjectLiteralThis: true,
|
|
725
|
+
}
|
|
726
|
+
: convertedValue,
|
|
727
|
+
shorthand: false,
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
for (const pendingAccessor of pendingAccessors) {
|
|
731
|
+
behaviorMembers.push(convertAccessorProperty(pendingAccessor.memberName, pendingAccessor.getter, pendingAccessor.setter, objectBehaviorContext, undefined));
|
|
732
|
+
}
|
|
430
733
|
// DETERMINISTIC TYPING: Object's inferredType comes from contextualType
|
|
431
734
|
// (which may be from LHS annotation or synthesized type).
|
|
432
735
|
// We don't derive from properties because that would require TS inference.
|
|
433
736
|
return {
|
|
434
737
|
kind: "object",
|
|
435
738
|
properties,
|
|
739
|
+
behaviorMembers: behaviorMembers.length > 0 ? behaviorMembers : undefined,
|
|
436
740
|
inferredType: contextualType, // Use contextual type if available
|
|
437
741
|
sourceSpan: getSourceSpan(node),
|
|
438
742
|
contextualType,
|