@alloy-js/csharp 0.20.0-dev.6 → 0.20.0-dev.8
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/src/components/access-expression/access-expression.d.ts +54 -0
- package/dist/src/components/access-expression/access-expression.d.ts.map +1 -0
- package/dist/src/components/access-expression/access-expression.js +277 -0
- package/dist/src/components/access-expression/access-expression.js.map +1 -0
- package/dist/src/components/access-expression/access-expression.test.d.ts +2 -0
- package/dist/src/components/access-expression/access-expression.test.d.ts.map +1 -0
- package/dist/src/components/access-expression/access-expression.test.js +336 -0
- package/dist/src/components/access-expression/access-expression.test.js.map +1 -0
- package/dist/src/components/access-expression/part-descriptors.d.ts +32 -0
- package/dist/src/components/access-expression/part-descriptors.d.ts.map +1 -0
- package/dist/src/components/access-expression/part-descriptors.js +99 -0
- package/dist/src/components/access-expression/part-descriptors.js.map +1 -0
- package/dist/src/components/index.d.ts +1 -0
- package/dist/src/components/index.d.ts.map +1 -1
- package/dist/src/components/index.js +1 -0
- package/dist/src/components/index.js.map +1 -1
- package/dist/src/components/invocation-expression/invocation-expression.d.ts +29 -0
- package/dist/src/components/invocation-expression/invocation-expression.d.ts.map +1 -0
- package/dist/src/components/invocation-expression/invocation-expression.js +70 -0
- package/dist/src/components/invocation-expression/invocation-expression.js.map +1 -0
- package/dist/src/components/invocation-expression/invocation-expression.test.d.ts +2 -0
- package/dist/src/components/invocation-expression/invocation-expression.test.d.ts.map +1 -0
- package/dist/src/components/invocation-expression/invocation-expression.test.js +105 -0
- package/dist/src/components/invocation-expression/invocation-expression.test.js.map +1 -0
- package/dist/src/components/parameters/parameters.d.ts +1 -2
- package/dist/src/components/parameters/parameters.d.ts.map +1 -1
- package/dist/src/components/parameters/parameters.js +2 -1
- package/dist/src/components/parameters/parameters.js.map +1 -1
- package/dist/src/components/parameters/parameters.test.js +66 -0
- package/dist/src/components/parameters/parameters.test.js.map +1 -1
- package/dist/src/components/property/property.d.ts +2 -2
- package/dist/src/components/property/property.d.ts.map +1 -1
- package/dist/src/components/property/property.js +10 -3
- package/dist/src/components/property/property.js.map +1 -1
- package/dist/src/scopes/csharp.d.ts +2 -0
- package/dist/src/scopes/csharp.d.ts.map +1 -1
- package/dist/src/scopes/csharp.js +3 -0
- package/dist/src/scopes/csharp.js.map +1 -1
- package/dist/src/symbols/csharp.d.ts +11 -0
- package/dist/src/symbols/csharp.d.ts.map +1 -1
- package/dist/src/symbols/csharp.js +23 -0
- package/dist/src/symbols/csharp.js.map +1 -1
- package/dist/src/symbols/reference.d.ts +2 -2
- package/dist/src/symbols/reference.d.ts.map +1 -1
- package/dist/src/symbols/reference.js +17 -5
- package/dist/src/symbols/reference.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/components/access-expression/access-expression.test.tsx +284 -0
- package/src/components/access-expression/access-expression.tsx +375 -0
- package/src/components/access-expression/part-descriptors.ts +175 -0
- package/src/components/index.ts +1 -0
- package/src/components/invocation-expression/invocation-expression.test.tsx +101 -0
- package/src/components/invocation-expression/invocation-expression.tsx +60 -0
- package/src/components/parameters/parameters.test.tsx +46 -0
- package/src/components/parameters/parameters.tsx +2 -2
- package/src/components/property/property.tsx +8 -2
- package/src/scopes/csharp.ts +5 -0
- package/src/symbols/csharp.ts +32 -0
- package/src/symbols/{reference.ts → reference.tsx} +11 -9
- package/temp/api.json +268 -33
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import { ClassDeclaration } from "#components/class/declaration.jsx";
|
|
2
|
+
import { Method } from "#components/method/method.jsx";
|
|
3
|
+
import { TestNamespace } from "#test/utils.jsx";
|
|
4
|
+
import { List, namekey, printTree, renderTree } from "@alloy-js/core";
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
import { CSharpSymbol } from "../../symbols/csharp.js";
|
|
7
|
+
import { AccessExpression } from "./access-expression.jsx";
|
|
8
|
+
|
|
9
|
+
it("makes a member access expression", () => {
|
|
10
|
+
const template = (
|
|
11
|
+
<AccessExpression>
|
|
12
|
+
<AccessExpression.Part id="Foo" />
|
|
13
|
+
<AccessExpression.Part id="Bar" />
|
|
14
|
+
</AccessExpression>
|
|
15
|
+
);
|
|
16
|
+
expect(template).toRenderTo(`Foo.Bar`);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("makes an element access expression", () => {
|
|
20
|
+
const template = (
|
|
21
|
+
<AccessExpression>
|
|
22
|
+
<AccessExpression.Part id="Foo" />
|
|
23
|
+
<AccessExpression.Part index={1} />
|
|
24
|
+
</AccessExpression>
|
|
25
|
+
);
|
|
26
|
+
expect(template).toRenderTo(`Foo[1]`);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("makes a call expression", () => {
|
|
30
|
+
const template = (
|
|
31
|
+
<AccessExpression>
|
|
32
|
+
<AccessExpression.Part id="Foo" />
|
|
33
|
+
<AccessExpression.Part args={[1, 2, 3]} />
|
|
34
|
+
</AccessExpression>
|
|
35
|
+
);
|
|
36
|
+
expect(template).toRenderTo(`Foo(1, 2, 3)`);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("makes an id part from a symbol", () => {
|
|
40
|
+
const symbol = new CSharpSymbol("Symbol", undefined);
|
|
41
|
+
const template = (
|
|
42
|
+
<AccessExpression>
|
|
43
|
+
<AccessExpression.Part id="Foo" />
|
|
44
|
+
<AccessExpression.Part symbol={symbol} />
|
|
45
|
+
</AccessExpression>
|
|
46
|
+
);
|
|
47
|
+
expect(template).toRenderTo(`Foo.Symbol`);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("makes an id part from a symbol reactively", () => {
|
|
51
|
+
const symbol = new CSharpSymbol("Symbol", undefined);
|
|
52
|
+
const tree = renderTree(
|
|
53
|
+
<AccessExpression>
|
|
54
|
+
<AccessExpression.Part id="Foo" />
|
|
55
|
+
<AccessExpression.Part symbol={symbol} />
|
|
56
|
+
</AccessExpression>,
|
|
57
|
+
);
|
|
58
|
+
expect(printTree(tree)).toEqual("Foo.Symbol");
|
|
59
|
+
symbol.name = "Bar";
|
|
60
|
+
expect(printTree(tree)).toEqual("Foo.Bar");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("makes an id part from refkey, where the first part is a full reference, and subsequent parts are just the id", () => {
|
|
64
|
+
const methodKey = namekey("method");
|
|
65
|
+
const template = (
|
|
66
|
+
<TestNamespace>
|
|
67
|
+
<List>
|
|
68
|
+
<ClassDeclaration name="MyClass">
|
|
69
|
+
<Method name={methodKey} />
|
|
70
|
+
</ClassDeclaration>
|
|
71
|
+
<AccessExpression>
|
|
72
|
+
<AccessExpression.Part refkey={methodKey} />
|
|
73
|
+
<AccessExpression.Part refkey={methodKey} />
|
|
74
|
+
</AccessExpression>
|
|
75
|
+
</List>
|
|
76
|
+
</TestNamespace>
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
expect(template).toRenderTo(`
|
|
80
|
+
class MyClass
|
|
81
|
+
{
|
|
82
|
+
void Method() {}
|
|
83
|
+
}
|
|
84
|
+
MyClass.Method.Method
|
|
85
|
+
`);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("takes type args", () => {
|
|
89
|
+
const template = (
|
|
90
|
+
<AccessExpression>
|
|
91
|
+
<AccessExpression.Part id="Foo" typeArgs={["Foo", "Bar"]} />
|
|
92
|
+
</AccessExpression>
|
|
93
|
+
);
|
|
94
|
+
expect(template).toRenderTo(`Foo<Foo, Bar>`);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("takes multiple indexer arguments", () => {
|
|
98
|
+
const template = (
|
|
99
|
+
<AccessExpression>
|
|
100
|
+
<AccessExpression.Part id="Foo" />
|
|
101
|
+
<AccessExpression.Part indexerArgs={["arg1", "arg2"]} />
|
|
102
|
+
</AccessExpression>
|
|
103
|
+
);
|
|
104
|
+
expect(template).toRenderTo(`Foo[arg1, arg2]`);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("allows nullable member access", () => {
|
|
108
|
+
const template = (
|
|
109
|
+
<AccessExpression>
|
|
110
|
+
<AccessExpression.Part id="Foo" nullable />
|
|
111
|
+
<AccessExpression.Part id="Bar" />
|
|
112
|
+
</AccessExpression>
|
|
113
|
+
);
|
|
114
|
+
expect(template).toRenderTo(`Foo?.Bar`);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("allows conditional member access", () => {
|
|
118
|
+
const template = (
|
|
119
|
+
<AccessExpression>
|
|
120
|
+
<AccessExpression.Part id="Foo" />
|
|
121
|
+
<AccessExpression.Part id="Bar" conditional />
|
|
122
|
+
</AccessExpression>
|
|
123
|
+
);
|
|
124
|
+
expect(template).toRenderTo(`Foo?.Bar`);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("allows nullable element access", () => {
|
|
128
|
+
const template = (
|
|
129
|
+
<AccessExpression>
|
|
130
|
+
<AccessExpression.Part id="Foo" nullable />
|
|
131
|
+
<AccessExpression.Part index={1} />
|
|
132
|
+
</AccessExpression>
|
|
133
|
+
);
|
|
134
|
+
expect(template).toRenderTo(`Foo?[1]`);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("allows conditional element access", () => {
|
|
138
|
+
const template = (
|
|
139
|
+
<AccessExpression>
|
|
140
|
+
<AccessExpression.Part id="Foo" />
|
|
141
|
+
<AccessExpression.Part index={1} conditional />
|
|
142
|
+
</AccessExpression>
|
|
143
|
+
);
|
|
144
|
+
expect(template).toRenderTo(`Foo?[1]`);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it("uses symbol information for nullability", () => {
|
|
148
|
+
const symbol = new CSharpSymbol("Symbol", undefined, { isNullable: true });
|
|
149
|
+
|
|
150
|
+
const typeSymbol = new CSharpSymbol("SomeType", undefined, {
|
|
151
|
+
isNullable: true,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const typedSymbol = new CSharpSymbol("SomeValue", undefined, {
|
|
155
|
+
type: typeSymbol,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const template = (
|
|
159
|
+
<AccessExpression>
|
|
160
|
+
<AccessExpression.Part symbol={symbol} />
|
|
161
|
+
<AccessExpression.Part symbol={typedSymbol} />
|
|
162
|
+
<AccessExpression.Part id="Foo" />
|
|
163
|
+
</AccessExpression>
|
|
164
|
+
);
|
|
165
|
+
expect(template).toRenderTo(`Symbol?.SomeValue?.Foo`);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe("formatting", () => {
|
|
169
|
+
it("breaks long identifier chains", () => {
|
|
170
|
+
const template = (
|
|
171
|
+
<AccessExpression>
|
|
172
|
+
<AccessExpression.Part id="Foo" />
|
|
173
|
+
<AccessExpression.Part id="Foo" />
|
|
174
|
+
<AccessExpression.Part id="Foo" />
|
|
175
|
+
<AccessExpression.Part id="Foo" />
|
|
176
|
+
<AccessExpression.Part id="Foo" />
|
|
177
|
+
<AccessExpression.Part id="Foo" />
|
|
178
|
+
</AccessExpression>
|
|
179
|
+
);
|
|
180
|
+
expect(template).toRenderTo(
|
|
181
|
+
`
|
|
182
|
+
Foo.Foo
|
|
183
|
+
.Foo.Foo
|
|
184
|
+
.Foo.Foo
|
|
185
|
+
`,
|
|
186
|
+
{ printWidth: 10 },
|
|
187
|
+
);
|
|
188
|
+
});
|
|
189
|
+
it("breaks long call expressions", () => {
|
|
190
|
+
const template = (
|
|
191
|
+
<AccessExpression>
|
|
192
|
+
<AccessExpression.Part id="Foo" />
|
|
193
|
+
<AccessExpression.Part id="Bar" />
|
|
194
|
+
<AccessExpression.Part args={["variable1", "variable2", "variable3"]} />
|
|
195
|
+
</AccessExpression>
|
|
196
|
+
);
|
|
197
|
+
expect(template).toRenderTo(
|
|
198
|
+
`
|
|
199
|
+
Foo.Bar(
|
|
200
|
+
variable1,
|
|
201
|
+
variable2,
|
|
202
|
+
variable3
|
|
203
|
+
)
|
|
204
|
+
`,
|
|
205
|
+
{ printWidth: 10 },
|
|
206
|
+
);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it("breaks long type args", () => {
|
|
210
|
+
const template = (
|
|
211
|
+
<AccessExpression>
|
|
212
|
+
<AccessExpression.Part
|
|
213
|
+
id="Foo"
|
|
214
|
+
typeArgs={["Foo", "Bar", "Baz", "Qux"]}
|
|
215
|
+
/>
|
|
216
|
+
</AccessExpression>
|
|
217
|
+
);
|
|
218
|
+
expect(template).toRenderTo(
|
|
219
|
+
`
|
|
220
|
+
Foo<
|
|
221
|
+
Foo,
|
|
222
|
+
Bar,
|
|
223
|
+
Baz,
|
|
224
|
+
Qux
|
|
225
|
+
>
|
|
226
|
+
`,
|
|
227
|
+
{ printWidth: 10 },
|
|
228
|
+
);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it("breaks long type args for second member", () => {
|
|
232
|
+
const template = (
|
|
233
|
+
<AccessExpression>
|
|
234
|
+
<AccessExpression.Part id="Foo" />
|
|
235
|
+
<AccessExpression.Part
|
|
236
|
+
id="Bar"
|
|
237
|
+
typeArgs={["Foo", "Bar", "Baz", "Qux"]}
|
|
238
|
+
/>
|
|
239
|
+
</AccessExpression>
|
|
240
|
+
);
|
|
241
|
+
expect(template).toRenderTo(
|
|
242
|
+
`
|
|
243
|
+
Foo
|
|
244
|
+
.Bar<
|
|
245
|
+
Foo,
|
|
246
|
+
Bar,
|
|
247
|
+
Baz,
|
|
248
|
+
Qux
|
|
249
|
+
>
|
|
250
|
+
`,
|
|
251
|
+
{ printWidth: 10 },
|
|
252
|
+
);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("formats builder pattern", () => {
|
|
256
|
+
const template = (
|
|
257
|
+
<AccessExpression>
|
|
258
|
+
<AccessExpression.Part id="Foo" />
|
|
259
|
+
<AccessExpression.Part id="Bar" />
|
|
260
|
+
<AccessExpression.Part id="Baz" />
|
|
261
|
+
<AccessExpression.Part args />
|
|
262
|
+
<AccessExpression.Part id="Qux" />
|
|
263
|
+
<AccessExpression.Part id="Quux" typeArgs={["TTypeOne", "TTypeTwo"]} />
|
|
264
|
+
<AccessExpression.Part indexerArgs={["arg1", "arg2"]} />
|
|
265
|
+
<AccessExpression.Part args />
|
|
266
|
+
</AccessExpression>
|
|
267
|
+
);
|
|
268
|
+
expect(template).toRenderTo(
|
|
269
|
+
`
|
|
270
|
+
Foo.Bar
|
|
271
|
+
.Baz()
|
|
272
|
+
.Qux
|
|
273
|
+
.Quux<
|
|
274
|
+
TTypeOne,
|
|
275
|
+
TTypeTwo
|
|
276
|
+
>[
|
|
277
|
+
arg1,
|
|
278
|
+
arg2
|
|
279
|
+
]()
|
|
280
|
+
`,
|
|
281
|
+
{ printWidth: 10 },
|
|
282
|
+
);
|
|
283
|
+
});
|
|
284
|
+
});
|
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Children,
|
|
3
|
+
childrenArray,
|
|
4
|
+
ComponentDefinition,
|
|
5
|
+
computed,
|
|
6
|
+
For,
|
|
7
|
+
isComponentCreator,
|
|
8
|
+
Refkey,
|
|
9
|
+
Show,
|
|
10
|
+
takeSymbols,
|
|
11
|
+
} from "@alloy-js/core";
|
|
12
|
+
import { CSharpSymbol } from "../../symbols/csharp.js";
|
|
13
|
+
import {
|
|
14
|
+
childrenToPartDescriptors,
|
|
15
|
+
isArgsPart,
|
|
16
|
+
isIdPart,
|
|
17
|
+
PartDescriptor,
|
|
18
|
+
PartDescriptorWithArgs,
|
|
19
|
+
PartDescriptorWithId,
|
|
20
|
+
PartDescriptorWithIndex,
|
|
21
|
+
} from "./part-descriptors.js";
|
|
22
|
+
|
|
23
|
+
export interface AccessExpressionProps {
|
|
24
|
+
children: Children;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function AccessExpression(props: AccessExpressionProps) {
|
|
28
|
+
const children = flattenAccessExpression(childrenArray(() => props.children));
|
|
29
|
+
const parts = childrenToPartDescriptors(children);
|
|
30
|
+
|
|
31
|
+
// any symbols emitted from the children won't be relevant to parent scopes.
|
|
32
|
+
takeSymbols();
|
|
33
|
+
|
|
34
|
+
if (parts.length === 0) {
|
|
35
|
+
return <></>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const isCallChain = computed(() => {
|
|
39
|
+
let callCount = 0;
|
|
40
|
+
for (const part of parts) {
|
|
41
|
+
if (isArgsPart(part)) callCount++;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return callCount > 1;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// construct a member expression from the parts. When a part is nullish,
|
|
48
|
+
// and there is a subsequent part, we use `?.` instead of `.`. accessStyle determines
|
|
49
|
+
// whether we use dot or bracket notation.
|
|
50
|
+
|
|
51
|
+
return computed(() => {
|
|
52
|
+
return isCallChain.value ?
|
|
53
|
+
formatCallChain(parts)
|
|
54
|
+
: formatNonCallChain(parts);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Flattens nested access expressions into a single array of parts.
|
|
60
|
+
*/
|
|
61
|
+
function flattenAccessExpression(children: Children[]): Children[] {
|
|
62
|
+
const flattened: Children[] = [];
|
|
63
|
+
for (const child of children) {
|
|
64
|
+
if (isComponentCreator(child, AccessExpression)) {
|
|
65
|
+
flattened.push(
|
|
66
|
+
...flattenAccessExpression(childrenArray(() => child.props.children)),
|
|
67
|
+
);
|
|
68
|
+
} else {
|
|
69
|
+
flattened.push(child);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return flattened;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface AccessExpressionPartProps {
|
|
76
|
+
children?: Children;
|
|
77
|
+
/**
|
|
78
|
+
* Whether this part should use conditional access.
|
|
79
|
+
*/
|
|
80
|
+
conditional?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Emit a function call.
|
|
83
|
+
*/
|
|
84
|
+
args?: boolean | Children[];
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Type arguments to pass to a member access.
|
|
88
|
+
*/
|
|
89
|
+
typeArgs?: Children[];
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* A refkey for the symbol whose name becomes this part's identifier. When a refkey is provided for the first
|
|
93
|
+
* part, it will be fully resolved. Otherwise, just the symbol's name is used.
|
|
94
|
+
*/
|
|
95
|
+
refkey?: Refkey;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The symbol whose name becomes this part's identifier.
|
|
99
|
+
*/
|
|
100
|
+
symbol?: CSharpSymbol;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The identifier to use for this part.
|
|
104
|
+
*/
|
|
105
|
+
id?: string;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Create an element access part with a single indexer argument. Mutually
|
|
109
|
+
* exclusive with the `indexerArgs` prop.
|
|
110
|
+
*/
|
|
111
|
+
index?: Children;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Create an element access part with multiple indexer arguments. Mutually
|
|
115
|
+
* exclusive with the `index` prop.
|
|
116
|
+
*/
|
|
117
|
+
indexerArgs?: Children[];
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Whether this part could possibly be null. Will guard member and element
|
|
121
|
+
* access with a conditional access operator. Passing this is not necessary if
|
|
122
|
+
* you provide a symbol or refkey and the symbol's nullable flag is set.
|
|
123
|
+
*/
|
|
124
|
+
nullable?: boolean;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
AccessExpression.Part = function (props: AccessExpressionPartProps) {
|
|
128
|
+
/** renders nothing, the parent AccessExpression will use these args */
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Formatting of call chains (i.e. member expressions which have more than one
|
|
133
|
+
* call in them). The general approach is that line breaks occur after each
|
|
134
|
+
* call, and there is only one call per line. When there are non-call elements,
|
|
135
|
+
* they occur prior to the call part. The first part of the member expression
|
|
136
|
+
* contains all but the last non-call part.
|
|
137
|
+
*
|
|
138
|
+
* The following is an example of proper formatting:
|
|
139
|
+
*
|
|
140
|
+
* ```ts
|
|
141
|
+
* z.dummy // all but the last non-call part for the first element
|
|
142
|
+
* .object({ // the first call part with line break after
|
|
143
|
+
* a: 1,
|
|
144
|
+
* })
|
|
145
|
+
* .dummy.partial() // the next call part with non-call parts before it
|
|
146
|
+
* ```
|
|
147
|
+
*/
|
|
148
|
+
function formatCallChain(parts: PartDescriptor[]): Children {
|
|
149
|
+
return computed(() => {
|
|
150
|
+
const expression: Children[] = [];
|
|
151
|
+
|
|
152
|
+
// break the expression into parts.
|
|
153
|
+
const chunks: PartDescriptor[][] = [];
|
|
154
|
+
|
|
155
|
+
// the first part is all the non-call parts
|
|
156
|
+
let partIndex = 0;
|
|
157
|
+
|
|
158
|
+
function pushPart() {
|
|
159
|
+
const part = parts[partIndex];
|
|
160
|
+
if (!part) throw new Error("No part to push");
|
|
161
|
+
chunks.at(-1)!.push(part);
|
|
162
|
+
partIndex++;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function pushChunk() {
|
|
166
|
+
chunks.push([]);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// For the first chunk, take all the non-call parts except the last one
|
|
170
|
+
// and put them in a chunk.
|
|
171
|
+
pushChunk();
|
|
172
|
+
while (
|
|
173
|
+
partIndex < parts.length &&
|
|
174
|
+
(partIndex === parts.length - 1 ||
|
|
175
|
+
chunks.at(-1)!.length === 0 ||
|
|
176
|
+
!isArgsPart(parts[partIndex + 1]))
|
|
177
|
+
) {
|
|
178
|
+
pushPart();
|
|
179
|
+
if (isArgsPart(chunks.at(-1)!.at(-1)!)) {
|
|
180
|
+
// the first segment always ends after we see a call
|
|
181
|
+
// if we happen to take one
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// then for all remaining parts, collect all the non-call parts and end with
|
|
187
|
+
// a call chunk
|
|
188
|
+
while (partIndex < parts.length) {
|
|
189
|
+
pushChunk();
|
|
190
|
+
while (partIndex < parts.length && !isArgsPart(parts[partIndex])) {
|
|
191
|
+
pushPart();
|
|
192
|
+
}
|
|
193
|
+
while (partIndex < parts.length && isArgsPart(parts[partIndex])) {
|
|
194
|
+
pushPart();
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
for (let chunkIndex = 0; chunkIndex < chunks.length; chunkIndex++) {
|
|
199
|
+
const chunk = chunks[chunkIndex];
|
|
200
|
+
const chunkExpression = [];
|
|
201
|
+
for (let partIndex = 0; partIndex < chunk.length; partIndex++) {
|
|
202
|
+
if (chunkIndex === 0 && partIndex === 0) {
|
|
203
|
+
// first part is just gonna be the id
|
|
204
|
+
const firstPart =
|
|
205
|
+
isIdPart(chunk[0]) ?
|
|
206
|
+
chunk[0].id
|
|
207
|
+
: (chunk[0] as PartDescriptorWithIndex).indexerArgs;
|
|
208
|
+
chunkExpression.push(firstPart);
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const part = chunk[partIndex];
|
|
212
|
+
const prevPart =
|
|
213
|
+
partIndex === 0 ?
|
|
214
|
+
chunks[chunkIndex - 1].at(-1)!
|
|
215
|
+
: chunk[partIndex - 1];
|
|
216
|
+
|
|
217
|
+
if (isArgsPart(part)) {
|
|
218
|
+
// For parts with only args (no name), append function call directly with appropriate nullish operator
|
|
219
|
+
chunkExpression.push(formatCallExpr(prevPart, part));
|
|
220
|
+
} else if (isIdPart(part)) {
|
|
221
|
+
chunkExpression.push(formatMemberAccess(prevPart, part, true));
|
|
222
|
+
} else {
|
|
223
|
+
// bracket notation - don't include the dot
|
|
224
|
+
chunkExpression.push(formatElementAccess(prevPart, part));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
expression.push(
|
|
229
|
+
chunkIndex === 0 ? chunkExpression : (
|
|
230
|
+
<>
|
|
231
|
+
<sbr />
|
|
232
|
+
{chunkExpression}
|
|
233
|
+
</>
|
|
234
|
+
),
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return (
|
|
239
|
+
<group>
|
|
240
|
+
<indent>{expression}</indent>
|
|
241
|
+
</group>
|
|
242
|
+
);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function formatNonCallChain(parts: PartDescriptor[]): Children {
|
|
247
|
+
return computed(() => {
|
|
248
|
+
const expression: Children[] = [];
|
|
249
|
+
|
|
250
|
+
for (let i = 0; i < parts.length; i++) {
|
|
251
|
+
const part = parts[i];
|
|
252
|
+
const base =
|
|
253
|
+
isIdPart(part) ?
|
|
254
|
+
part.id
|
|
255
|
+
: (part as PartDescriptorWithIndex).indexerArgs;
|
|
256
|
+
if (i === 0) {
|
|
257
|
+
expression.push(base, <TypeArgs args={(part as any).typeArgs} />);
|
|
258
|
+
} else {
|
|
259
|
+
// Determine if we should use nullish operator from previous part
|
|
260
|
+
const prevPart = parts[i - 1];
|
|
261
|
+
|
|
262
|
+
if (isArgsPart(part)) {
|
|
263
|
+
// For parts with only args (no name), append function call directly with appropriate nullish operator
|
|
264
|
+
expression.push(formatCallExpr(prevPart, part));
|
|
265
|
+
} else if (isIdPart(part)) {
|
|
266
|
+
expression.push(formatMemberAccess(prevPart, part));
|
|
267
|
+
} else {
|
|
268
|
+
// bracket notation - don't include the dot
|
|
269
|
+
expression.push(formatElementAccess(prevPart, part));
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return expression;
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function formatElementAccess(
|
|
279
|
+
prevPart: PartDescriptor,
|
|
280
|
+
part: PartDescriptorWithIndex,
|
|
281
|
+
) {
|
|
282
|
+
return (
|
|
283
|
+
<group>
|
|
284
|
+
{part.conditional || ("nullable" in prevPart && prevPart.nullable) ?
|
|
285
|
+
"?"
|
|
286
|
+
: ""}
|
|
287
|
+
[
|
|
288
|
+
<indent>
|
|
289
|
+
<sbr />
|
|
290
|
+
<For each={part.indexerArgs} comma line>
|
|
291
|
+
{(arg) => arg}
|
|
292
|
+
</For>
|
|
293
|
+
</indent>
|
|
294
|
+
<sbr />]
|
|
295
|
+
</group>
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function formatMemberAccess(
|
|
300
|
+
prevPart: PartDescriptor,
|
|
301
|
+
part: PartDescriptorWithId,
|
|
302
|
+
noIndent = false,
|
|
303
|
+
) {
|
|
304
|
+
let Wrapping: ComponentDefinition<{ children: Children }>;
|
|
305
|
+
if (noIndent) {
|
|
306
|
+
Wrapping = function (props) {
|
|
307
|
+
return (
|
|
308
|
+
<group>
|
|
309
|
+
<sbr />
|
|
310
|
+
{props.children}
|
|
311
|
+
</group>
|
|
312
|
+
);
|
|
313
|
+
};
|
|
314
|
+
} else {
|
|
315
|
+
Wrapping = function (props) {
|
|
316
|
+
return (
|
|
317
|
+
<group>
|
|
318
|
+
<indent>
|
|
319
|
+
<sbr />
|
|
320
|
+
{props.children}
|
|
321
|
+
</indent>
|
|
322
|
+
</group>
|
|
323
|
+
);
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return (
|
|
328
|
+
<Wrapping>
|
|
329
|
+
{part.conditional || ("nullable" in prevPart && prevPart.nullable) ?
|
|
330
|
+
"?."
|
|
331
|
+
: "."}
|
|
332
|
+
{isIdPart(part) ? part.id : (part as PartDescriptorWithIndex).indexerArgs}
|
|
333
|
+
<TypeArgs args={part.typeArgs} />
|
|
334
|
+
</Wrapping>
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function TypeArgs(props: { args?: Children[] }) {
|
|
339
|
+
return (
|
|
340
|
+
<Show when={props.args && props.args.length > 0}>
|
|
341
|
+
{"<"}
|
|
342
|
+
<group>
|
|
343
|
+
<indent>
|
|
344
|
+
<sbr />
|
|
345
|
+
<For each={props.args!} comma line>
|
|
346
|
+
{(arg) => arg}
|
|
347
|
+
</For>
|
|
348
|
+
</indent>
|
|
349
|
+
<sbr />
|
|
350
|
+
</group>
|
|
351
|
+
{">"}
|
|
352
|
+
</Show>
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function formatCallExpr(
|
|
357
|
+
prevPart: PartDescriptor,
|
|
358
|
+
part: PartDescriptorWithArgs,
|
|
359
|
+
) {
|
|
360
|
+
return (
|
|
361
|
+
<group>
|
|
362
|
+
(<Show when={part.args.length <= 1}>{part.args[0]}</Show>
|
|
363
|
+
<Show when={part.args.length > 1}>
|
|
364
|
+
<indent>
|
|
365
|
+
<sbr />
|
|
366
|
+
<For each={part.args} comma line>
|
|
367
|
+
{(arg) => arg}
|
|
368
|
+
</For>
|
|
369
|
+
</indent>
|
|
370
|
+
<sbr />
|
|
371
|
+
</Show>
|
|
372
|
+
)
|
|
373
|
+
</group>
|
|
374
|
+
);
|
|
375
|
+
}
|