@alloy-js/csharp 0.20.0-dev.6 → 0.20.0-dev.9
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/class/declaration.test.js +1 -1
- package/dist/src/components/enum/declaration.ref.test.js +1 -1
- package/dist/src/components/index.d.ts +2 -1
- package/dist/src/components/index.d.ts.map +1 -1
- package/dist/src/components/index.js +2 -1
- 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/namespace.ref.test.js +1 -1
- package/dist/src/components/namespace.test.js +1 -1
- 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/components/{SourceFile.d.ts → source-file/source-file.d.ts} +3 -2
- package/dist/src/components/source-file/source-file.d.ts.map +1 -0
- package/dist/src/components/{SourceFile.js → source-file/source-file.js} +18 -13
- package/dist/src/components/source-file/source-file.js.map +1 -0
- package/dist/src/components/source-file/source-file.test.d.ts +2 -0
- package/dist/src/components/source-file/source-file.test.d.ts.map +1 -0
- package/dist/src/components/source-file/source-file.test.js +136 -0
- package/dist/src/components/source-file/source-file.test.js.map +1 -0
- package/dist/src/contexts/format-options.d.ts +5 -0
- package/dist/src/contexts/format-options.d.ts.map +1 -0
- package/dist/src/contexts/format-options.js +9 -0
- package/dist/src/contexts/format-options.js.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.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/class/declaration.test.tsx +1 -1
- package/src/components/enum/declaration.ref.test.tsx +1 -1
- package/src/components/index.ts +2 -1
- package/src/components/invocation-expression/invocation-expression.test.tsx +101 -0
- package/src/components/invocation-expression/invocation-expression.tsx +60 -0
- package/src/components/namespace.ref.test.tsx +1 -1
- package/src/components/namespace.test.tsx +1 -1
- 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/components/source-file/source-file.test.tsx +96 -0
- package/src/components/{SourceFile.tsx → source-file/source-file.tsx} +20 -10
- package/src/contexts/format-options.ts +14 -0
- package/src/index.ts +1 -0
- 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 +423 -37
- package/dist/src/components/SourceFile.d.ts.map +0 -1
- package/dist/src/components/SourceFile.js.map +0 -1
- package/dist/test/sourcefile.test.d.ts +0 -2
- package/dist/test/sourcefile.test.d.ts.map +0 -1
- package/dist/test/sourcefile.test.js +0 -47
- package/dist/test/sourcefile.test.js.map +0 -1
- package/test/sourcefile.test.tsx +0 -33
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Children,
|
|
3
|
+
computed,
|
|
4
|
+
isComponentCreator,
|
|
5
|
+
reactive,
|
|
6
|
+
ref,
|
|
7
|
+
symbolForRefkey,
|
|
8
|
+
ToRefs,
|
|
9
|
+
} from "@alloy-js/core";
|
|
10
|
+
import { CSharpSymbol } from "../../index.js";
|
|
11
|
+
import {
|
|
12
|
+
AccessExpression,
|
|
13
|
+
AccessExpressionPartProps,
|
|
14
|
+
} from "./access-expression.jsx";
|
|
15
|
+
|
|
16
|
+
export interface PartDescriptorWithId extends PartDescriptorBase {
|
|
17
|
+
/**
|
|
18
|
+
* The identifier of the access expression part. Will use member access, so must be a valid
|
|
19
|
+
* C# identifier.
|
|
20
|
+
*/
|
|
21
|
+
id: Children;
|
|
22
|
+
conditional: boolean;
|
|
23
|
+
typeArgs?: Children[];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function isIdPart(part: PartDescriptor): part is PartDescriptorWithId {
|
|
27
|
+
return "id" in part && part.id !== undefined;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface PartDescriptorWithIndex extends PartDescriptorBase {
|
|
31
|
+
/**
|
|
32
|
+
* The index of the access expression part. Will use element access.
|
|
33
|
+
*/
|
|
34
|
+
indexerArgs: Children[];
|
|
35
|
+
conditional: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function isIndexPart(
|
|
39
|
+
part: PartDescriptor,
|
|
40
|
+
): part is PartDescriptorWithIndex {
|
|
41
|
+
return "indexerArgs" in part && part.indexerArgs !== undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface PartDescriptorWithArgs extends PartDescriptorBase {
|
|
45
|
+
args: Children[];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function isArgsPart(
|
|
49
|
+
part: PartDescriptor,
|
|
50
|
+
): part is PartDescriptorWithArgs {
|
|
51
|
+
return "args" in part && part.args !== undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface PartDescriptorBase {
|
|
55
|
+
nullable: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type PartDescriptor =
|
|
59
|
+
| PartDescriptorWithId
|
|
60
|
+
| PartDescriptorWithIndex
|
|
61
|
+
| PartDescriptorWithArgs;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Build part descriptors from the children of a MemberExpression.
|
|
65
|
+
*/
|
|
66
|
+
export function childrenToPartDescriptors(
|
|
67
|
+
children: Children[],
|
|
68
|
+
): PartDescriptor[] {
|
|
69
|
+
const parts: PartDescriptor[] = [];
|
|
70
|
+
for (const child of children) {
|
|
71
|
+
if (!isComponentCreator(child, AccessExpression.Part)) {
|
|
72
|
+
// we ignore non-parts
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
parts.push(
|
|
77
|
+
createPartDescriptorFromProps(child.props, child === children[0]),
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return parts;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const exclusiveParts: (keyof AccessExpressionPartProps)[] = [
|
|
85
|
+
"children",
|
|
86
|
+
"args",
|
|
87
|
+
"refkey",
|
|
88
|
+
"symbol",
|
|
89
|
+
"id",
|
|
90
|
+
];
|
|
91
|
+
/**
|
|
92
|
+
* Creates a reactive part descriptor from the given part props.
|
|
93
|
+
*
|
|
94
|
+
* @param partProps The props for the part.
|
|
95
|
+
* @param first Whether this is the first part in the expression. Refkeys are
|
|
96
|
+
* handled specially for the first part.
|
|
97
|
+
*/
|
|
98
|
+
function createPartDescriptorFromProps(
|
|
99
|
+
partProps: AccessExpressionPartProps,
|
|
100
|
+
first: boolean,
|
|
101
|
+
) {
|
|
102
|
+
const foundProps = exclusiveParts.filter((key) => {
|
|
103
|
+
return key in partProps;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (foundProps.length > 1) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
`Only one of ${foundProps.join(", ")} can be used for a MemberExpression part at a time`,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const symbolSource = computed(() => {
|
|
113
|
+
if (partProps.refkey) {
|
|
114
|
+
return symbolForRefkey(partProps.refkey).value as CSharpSymbol;
|
|
115
|
+
} else if (partProps.symbol) {
|
|
116
|
+
return partProps.symbol;
|
|
117
|
+
} else {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const part: ToRefs<PartDescriptor> = {
|
|
123
|
+
id: computed(() => {
|
|
124
|
+
if (partProps.args || partProps.index || partProps.indexerArgs) {
|
|
125
|
+
return undefined;
|
|
126
|
+
} else if (partProps.children !== undefined) {
|
|
127
|
+
return partProps.children;
|
|
128
|
+
} else if (first && partProps.refkey) {
|
|
129
|
+
return partProps.refkey;
|
|
130
|
+
} else if (partProps.id !== undefined) {
|
|
131
|
+
return partProps.id;
|
|
132
|
+
} else if (symbolSource.value) {
|
|
133
|
+
return escapeId(symbolSource.value.name);
|
|
134
|
+
} else {
|
|
135
|
+
return "<unresolved symbol>";
|
|
136
|
+
}
|
|
137
|
+
}),
|
|
138
|
+
indexerArgs: computed(() => {
|
|
139
|
+
if (partProps.indexerArgs) {
|
|
140
|
+
return partProps.indexerArgs;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (partProps.index !== undefined) {
|
|
144
|
+
return [partProps.index];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return [];
|
|
148
|
+
}),
|
|
149
|
+
conditional: computed(() => {
|
|
150
|
+
return !!partProps.conditional;
|
|
151
|
+
}),
|
|
152
|
+
nullable: computed(() => {
|
|
153
|
+
if (partProps.nullable) {
|
|
154
|
+
return true;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (symbolSource.value) {
|
|
158
|
+
return symbolSource.value.isNullable;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return false;
|
|
162
|
+
}),
|
|
163
|
+
args: ref<any>(partProps.args === true ? [] : partProps.args),
|
|
164
|
+
typeArgs: ref<any>(partProps.typeArgs),
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
return reactive(part);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* replaces quotes with escaped quotes
|
|
172
|
+
*/
|
|
173
|
+
function escapeId(id: string) {
|
|
174
|
+
return id.replace(/"/g, '\\"');
|
|
175
|
+
}
|
|
@@ -19,7 +19,7 @@ import { Attribute } from "../attributes/attributes.jsx";
|
|
|
19
19
|
import { Field } from "../field/field.jsx";
|
|
20
20
|
import { Method } from "../method/method.jsx";
|
|
21
21
|
import { Property } from "../property/property.jsx";
|
|
22
|
-
import { SourceFile } from "../
|
|
22
|
+
import { SourceFile } from "../source-file/source-file.jsx";
|
|
23
23
|
import { TypeParameterProps } from "../type-parameters/type-parameter.jsx";
|
|
24
24
|
import { ClassDeclaration } from "./declaration.jsx";
|
|
25
25
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Namespace } from "#components/namespace.jsx";
|
|
2
|
-
import { SourceFile } from "#components/
|
|
2
|
+
import { SourceFile } from "#components/source-file/source-file.jsx";
|
|
3
3
|
import { Output, refkey } from "@alloy-js/core";
|
|
4
4
|
import { d } from "@alloy-js/core/testing";
|
|
5
5
|
import { expect, it } from "vitest";
|
package/src/components/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ export * from "./field/field.jsx";
|
|
|
10
10
|
export * from "./interface/declaration.js";
|
|
11
11
|
export * from "./interface/method.js";
|
|
12
12
|
export * from "./interface/property.js";
|
|
13
|
+
export * from "./invocation-expression/invocation-expression.jsx";
|
|
13
14
|
export * from "./lexical-scope.jsx";
|
|
14
15
|
export * from "./method-scope.jsx";
|
|
15
16
|
export * from "./method/method.jsx";
|
|
@@ -20,7 +21,7 @@ export * from "./ProjectDirectory.js";
|
|
|
20
21
|
export * from "./property/property.jsx";
|
|
21
22
|
export * from "./record/declaration.js";
|
|
22
23
|
export * from "./Reference.js";
|
|
23
|
-
export * from "./
|
|
24
|
+
export * from "./source-file/source-file.jsx";
|
|
24
25
|
export * from "./struct/declaration.jsx";
|
|
25
26
|
export type { TypeParameterProps } from "./type-parameters/type-parameter.jsx";
|
|
26
27
|
export * from "./UsingDirective.js";
|
|
@@ -0,0 +1,101 @@
|
|
|
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 { namekey } from "@alloy-js/core";
|
|
5
|
+
import { describe, expect, it } from "vitest";
|
|
6
|
+
import { InvocationExpression } from "./invocation-expression.jsx";
|
|
7
|
+
|
|
8
|
+
it("makes a call with no arguments", () => {
|
|
9
|
+
const template = <InvocationExpression target="Foo" />;
|
|
10
|
+
expect(template).toRenderTo(`Foo()`);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("makes a call with arguments", () => {
|
|
14
|
+
const template = (
|
|
15
|
+
<InvocationExpression target="Foo" args={["42", `"string"`]} />
|
|
16
|
+
);
|
|
17
|
+
expect(template).toRenderTo(`Foo(42, "string")`);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("makes a call with type parameters", () => {
|
|
21
|
+
const template = (
|
|
22
|
+
<InvocationExpression target="Foo" typeArgs={["Bar", "Baz"]} />
|
|
23
|
+
);
|
|
24
|
+
expect(template).toRenderTo(`Foo<Bar, Baz>()`);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("makes a call to a method", () => {
|
|
28
|
+
const cls = namekey("TestClass");
|
|
29
|
+
const method = namekey("Method");
|
|
30
|
+
const template = (
|
|
31
|
+
<TestNamespace>
|
|
32
|
+
<ClassDeclaration name={cls}>
|
|
33
|
+
<Method name={method}>return 1;</Method>
|
|
34
|
+
</ClassDeclaration>
|
|
35
|
+
<hbr />
|
|
36
|
+
<InvocationExpression target={method} />;
|
|
37
|
+
</TestNamespace>
|
|
38
|
+
);
|
|
39
|
+
expect(template).toRenderTo(`
|
|
40
|
+
class TestClass
|
|
41
|
+
{
|
|
42
|
+
void Method()
|
|
43
|
+
{
|
|
44
|
+
return 1;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
TestClass.Method();
|
|
48
|
+
`);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe("formatting", () => {
|
|
52
|
+
it("doesn't break one long argument", () => {
|
|
53
|
+
const template = (
|
|
54
|
+
<InvocationExpression target="Foo" args={["oneLongArgument"]} />
|
|
55
|
+
);
|
|
56
|
+
expect(template).toRenderTo(`Foo(oneLongArgument)`, { printWidth: 10 });
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("breaks multiple arguments", () => {
|
|
60
|
+
const template = (
|
|
61
|
+
<InvocationExpression
|
|
62
|
+
target="Foo"
|
|
63
|
+
args={["oneLongArgument", "anotherLongArgument"]}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
expect(template).toRenderTo(
|
|
67
|
+
`
|
|
68
|
+
Foo(
|
|
69
|
+
oneLongArgument,
|
|
70
|
+
anotherLongArgument
|
|
71
|
+
)
|
|
72
|
+
`,
|
|
73
|
+
{ printWidth: 10 },
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("doesn't break one long type argument", () => {
|
|
78
|
+
const template = (
|
|
79
|
+
<InvocationExpression target="Foo" typeArgs={["oneLongArgument"]} />
|
|
80
|
+
);
|
|
81
|
+
expect(template).toRenderTo(`Foo<oneLongArgument>()`, { printWidth: 10 });
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it("breaks multiple type arguments", () => {
|
|
85
|
+
const template = (
|
|
86
|
+
<InvocationExpression
|
|
87
|
+
target="Foo"
|
|
88
|
+
typeArgs={["oneLongArgument", "anotherLongArgument"]}
|
|
89
|
+
/>
|
|
90
|
+
);
|
|
91
|
+
expect(template).toRenderTo(
|
|
92
|
+
`
|
|
93
|
+
Foo<
|
|
94
|
+
oneLongArgument,
|
|
95
|
+
anotherLongArgument
|
|
96
|
+
>()
|
|
97
|
+
`,
|
|
98
|
+
{ printWidth: 10 },
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Children, For, Indent, Show, Wrap } from "@alloy-js/core";
|
|
2
|
+
|
|
3
|
+
export interface InvocationExpressionProps {
|
|
4
|
+
target: Children;
|
|
5
|
+
/**
|
|
6
|
+
* Arguments to pass to the invocation.
|
|
7
|
+
*/
|
|
8
|
+
args?: Children[];
|
|
9
|
+
/**
|
|
10
|
+
* Generic type arguments for the invocation.
|
|
11
|
+
*/
|
|
12
|
+
typeArgs?: Children[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A call to a function or method.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
*
|
|
20
|
+
* ```jsx
|
|
21
|
+
* <InvocationExpression target="Foo" typeArgs={["T"]} args={["x"]} />
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* Renders to:
|
|
25
|
+
*
|
|
26
|
+
* ```csharp
|
|
27
|
+
* Foo<T>("x");
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export function InvocationExpression(props: InvocationExpressionProps) {
|
|
31
|
+
return (
|
|
32
|
+
<group>
|
|
33
|
+
{props.target}
|
|
34
|
+
<Show when={!!props.typeArgs && props.typeArgs.length > 0}>
|
|
35
|
+
{"<"}
|
|
36
|
+
<Wrap
|
|
37
|
+
when={props.typeArgs!.length > 1}
|
|
38
|
+
with={Indent}
|
|
39
|
+
props={{ softline: true, trailingBreak: true }}
|
|
40
|
+
>
|
|
41
|
+
<For each={props.typeArgs ?? []} comma line>
|
|
42
|
+
{(typeArg) => typeArg}
|
|
43
|
+
</For>
|
|
44
|
+
</Wrap>
|
|
45
|
+
{">"}
|
|
46
|
+
</Show>
|
|
47
|
+
(
|
|
48
|
+
<Wrap
|
|
49
|
+
when={!!props.args && props.args.length > 1}
|
|
50
|
+
with={Indent}
|
|
51
|
+
props={{ softline: true, trailingBreak: true }}
|
|
52
|
+
>
|
|
53
|
+
<For each={props.args ?? []} comma line>
|
|
54
|
+
{(arg) => arg}
|
|
55
|
+
</For>
|
|
56
|
+
</Wrap>
|
|
57
|
+
)
|
|
58
|
+
</group>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -3,7 +3,7 @@ import { d } from "@alloy-js/core/testing";
|
|
|
3
3
|
import { expect, it } from "vitest";
|
|
4
4
|
import { ClassDeclaration } from "./class/declaration.jsx";
|
|
5
5
|
import { Namespace } from "./namespace.jsx";
|
|
6
|
-
import { SourceFile } from "./
|
|
6
|
+
import { SourceFile } from "./source-file/source-file.jsx";
|
|
7
7
|
|
|
8
8
|
it("references types in the same namespace", () => {
|
|
9
9
|
const classRef = refkey();
|
|
@@ -3,7 +3,7 @@ import { d } from "@alloy-js/core/testing";
|
|
|
3
3
|
import { expect, it } from "vitest";
|
|
4
4
|
import { ClassDeclaration } from "./class/declaration.jsx";
|
|
5
5
|
import { Namespace } from "./namespace.jsx";
|
|
6
|
-
import { SourceFile } from "./
|
|
6
|
+
import { SourceFile } from "./source-file/source-file.jsx";
|
|
7
7
|
|
|
8
8
|
it("defines multiple namespaces and source files with unique content", () => {
|
|
9
9
|
const tree = (
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ClassDeclaration } from "#components/class/declaration.jsx";
|
|
2
2
|
import { Method } from "#components/method/method.jsx";
|
|
3
|
+
import { Property } from "#components/property/property.jsx";
|
|
3
4
|
import { List, memberRefkey, namekey } from "@alloy-js/core";
|
|
4
5
|
import { Children } from "@alloy-js/core/jsx-runtime";
|
|
5
6
|
import { expect, it } from "vitest";
|
|
@@ -69,3 +70,48 @@ it("members can be referenced", () => {
|
|
|
69
70
|
}
|
|
70
71
|
`);
|
|
71
72
|
});
|
|
73
|
+
|
|
74
|
+
it("members can be referenced when the parameter is nullable", () => {
|
|
75
|
+
const propTypeKey = namekey("PropType");
|
|
76
|
+
const propTypePropKey = namekey("Field");
|
|
77
|
+
const classKey = namekey("TestType");
|
|
78
|
+
const propKey = namekey("TestProp");
|
|
79
|
+
const param1Key = namekey("param1");
|
|
80
|
+
|
|
81
|
+
expect(
|
|
82
|
+
<TestNamespace>
|
|
83
|
+
<List>
|
|
84
|
+
<ClassDeclaration name={propTypeKey}>
|
|
85
|
+
<Property name={propTypePropKey} type={"string"} nullable />
|
|
86
|
+
</ClassDeclaration>
|
|
87
|
+
<ClassDeclaration name={classKey}>
|
|
88
|
+
<Property name={propKey} type={propTypeKey} nullable />
|
|
89
|
+
</ClassDeclaration>
|
|
90
|
+
<ClassDeclaration name="Test">
|
|
91
|
+
<Method
|
|
92
|
+
name="Test"
|
|
93
|
+
parameters={[{ name: param1Key, type: classKey, optional: true }]}
|
|
94
|
+
>
|
|
95
|
+
return {memberRefkey(param1Key, propKey, propTypePropKey)};
|
|
96
|
+
</Method>
|
|
97
|
+
</ClassDeclaration>
|
|
98
|
+
</List>
|
|
99
|
+
</TestNamespace>,
|
|
100
|
+
).toRenderTo(`
|
|
101
|
+
class PropType
|
|
102
|
+
{
|
|
103
|
+
string? Field { }
|
|
104
|
+
}
|
|
105
|
+
class TestType
|
|
106
|
+
{
|
|
107
|
+
PropType? TestProp { }
|
|
108
|
+
}
|
|
109
|
+
class Test
|
|
110
|
+
{
|
|
111
|
+
void Test(TestType? param1)
|
|
112
|
+
{
|
|
113
|
+
return param1?.TestProp?.Field;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
`);
|
|
117
|
+
});
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
For,
|
|
7
7
|
Indent,
|
|
8
8
|
Namekey,
|
|
9
|
-
OutputSymbol,
|
|
10
9
|
Refkey,
|
|
11
10
|
} from "@alloy-js/core";
|
|
12
11
|
import { createParameterSymbol } from "../../symbols/factories.js";
|
|
@@ -19,8 +18,8 @@ export interface ParameterProps {
|
|
|
19
18
|
optional?: boolean;
|
|
20
19
|
/** Default value for the parameter */
|
|
21
20
|
default?: Children;
|
|
21
|
+
|
|
22
22
|
refkey?: Refkey;
|
|
23
|
-
symbol?: OutputSymbol;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
/** Define a parameter to be used in class or interface method. */
|
|
@@ -30,6 +29,7 @@ export function Parameter(props: ParameterProps) {
|
|
|
30
29
|
const memberSymbol = createParameterSymbol(props.name, {
|
|
31
30
|
refkeys: props.refkey,
|
|
32
31
|
type: TypeSlot.firstSymbol,
|
|
32
|
+
isNullable: props.optional,
|
|
33
33
|
});
|
|
34
34
|
|
|
35
35
|
return (
|
|
@@ -2,9 +2,11 @@ import {
|
|
|
2
2
|
Block,
|
|
3
3
|
Children,
|
|
4
4
|
code,
|
|
5
|
+
createSymbolSlot,
|
|
5
6
|
List,
|
|
6
7
|
MemberDeclaration,
|
|
7
8
|
MemberName,
|
|
9
|
+
Namekey,
|
|
8
10
|
Refkey,
|
|
9
11
|
} from "@alloy-js/core";
|
|
10
12
|
import {
|
|
@@ -48,7 +50,7 @@ const getModifiers = makeModifiers<PropertyModifiers>([
|
|
|
48
50
|
|
|
49
51
|
/** Properties for {@link Property} component */
|
|
50
52
|
export interface PropertyProps extends AccessModifiers, PropertyModifiers {
|
|
51
|
-
name: string;
|
|
53
|
+
name: Namekey | string;
|
|
52
54
|
refkey?: Refkey;
|
|
53
55
|
|
|
54
56
|
/** Property type */
|
|
@@ -115,8 +117,12 @@ export interface PropertyProps extends AccessModifiers, PropertyModifiers {
|
|
|
115
117
|
* ```
|
|
116
118
|
*/
|
|
117
119
|
export function Property(props: PropertyProps) {
|
|
120
|
+
const TypeSlot = createSymbolSlot();
|
|
121
|
+
|
|
118
122
|
const propertySymbol = createPropertySymbol(props.name, {
|
|
119
123
|
refkeys: props.refkey,
|
|
124
|
+
isNullable: props.nullable,
|
|
125
|
+
type: TypeSlot.firstSymbol,
|
|
120
126
|
});
|
|
121
127
|
|
|
122
128
|
const modifiers = computeModifiersPrefix([
|
|
@@ -135,7 +141,7 @@ export function Property(props: PropertyProps) {
|
|
|
135
141
|
<DocWhen doc={props.doc} />
|
|
136
142
|
<AttributeList attributes={props.attributes} endline />
|
|
137
143
|
{modifiers}
|
|
138
|
-
{props.type}
|
|
144
|
+
<TypeSlot>{props.type}</TypeSlot>
|
|
139
145
|
{props.nullable && "?"} <MemberName />{" "}
|
|
140
146
|
<Block newline inline>
|
|
141
147
|
<List joiner=" ">
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { ClassDeclaration } from "#components/class/declaration.jsx";
|
|
2
|
+
import { Namespace } from "#components/namespace.jsx";
|
|
3
|
+
import { Children, FormatOptions, Indent, Output, Prose } from "@alloy-js/core";
|
|
4
|
+
import { describe, expect, it } from "vitest";
|
|
5
|
+
import { CSharpFormatOptions } from "../../contexts/format-options.js";
|
|
6
|
+
import { SourceFile } from "./source-file.jsx";
|
|
7
|
+
|
|
8
|
+
it("defines multiple source files with unique content", () => {
|
|
9
|
+
expect(
|
|
10
|
+
<Output>
|
|
11
|
+
<Namespace name="TestCode">
|
|
12
|
+
<SourceFile path="Test1.cs">
|
|
13
|
+
<ClassDeclaration public name="TestClass1" />
|
|
14
|
+
</SourceFile>
|
|
15
|
+
<SourceFile path="Test2.cs">
|
|
16
|
+
<ClassDeclaration public name="TestClass2" />
|
|
17
|
+
</SourceFile>
|
|
18
|
+
</Namespace>
|
|
19
|
+
</Output>,
|
|
20
|
+
).toRenderTo({
|
|
21
|
+
"Test1.cs": `
|
|
22
|
+
namespace TestCode;
|
|
23
|
+
|
|
24
|
+
public class TestClass1;
|
|
25
|
+
`,
|
|
26
|
+
"Test2.cs": `
|
|
27
|
+
namespace TestCode;
|
|
28
|
+
|
|
29
|
+
public class TestClass2;
|
|
30
|
+
`,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe("format options", () => {
|
|
35
|
+
function FileWithFormatOptions(props: {
|
|
36
|
+
options: CSharpFormatOptions;
|
|
37
|
+
children: Children;
|
|
38
|
+
}) {
|
|
39
|
+
return (
|
|
40
|
+
<CSharpFormatOptions value={props.options}>
|
|
41
|
+
<SourceFile path="hi.cs">{props.children}</SourceFile>
|
|
42
|
+
</CSharpFormatOptions>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
it("respect tabWidth", () => {
|
|
47
|
+
expect(
|
|
48
|
+
<FileWithFormatOptions options={{ tabWidth: 5 }}>
|
|
49
|
+
hello
|
|
50
|
+
<Indent>indented 5 spaces</Indent>
|
|
51
|
+
</FileWithFormatOptions>,
|
|
52
|
+
).toRenderTo(`
|
|
53
|
+
hello
|
|
54
|
+
indented 5 spaces
|
|
55
|
+
`);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("respect useTabs", () => {
|
|
59
|
+
expect(
|
|
60
|
+
<FileWithFormatOptions options={{ useTabs: true }}>
|
|
61
|
+
hello
|
|
62
|
+
<Indent>indented with tabs</Indent>
|
|
63
|
+
</FileWithFormatOptions>,
|
|
64
|
+
).toRenderTo(`
|
|
65
|
+
hello
|
|
66
|
+
\tindented with tabs
|
|
67
|
+
`);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("respect printWidth", () => {
|
|
71
|
+
expect(
|
|
72
|
+
<FileWithFormatOptions options={{ printWidth: 10 }}>
|
|
73
|
+
<Prose>this is too long</Prose>
|
|
74
|
+
</FileWithFormatOptions>,
|
|
75
|
+
).toRenderTo(`
|
|
76
|
+
this is
|
|
77
|
+
too long
|
|
78
|
+
`);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("CSharpFormatOptions takes precedence over FormatOptions", () => {
|
|
82
|
+
expect(
|
|
83
|
+
<FormatOptions value={{ tabWidth: 5 }}>
|
|
84
|
+
<CSharpFormatOptions value={{ tabWidth: 3 }}>
|
|
85
|
+
<SourceFile path="hi.cs">
|
|
86
|
+
hello
|
|
87
|
+
<Indent>indented 3 spaces</Indent>
|
|
88
|
+
</SourceFile>
|
|
89
|
+
</CSharpFormatOptions>
|
|
90
|
+
</FormatOptions>,
|
|
91
|
+
).toRenderTo(`
|
|
92
|
+
hello
|
|
93
|
+
indented 3 spaces
|
|
94
|
+
`);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { NamespaceScopes } from "#components/namespace-scopes.jsx";
|
|
2
|
+
import { Reference } from "#components/Reference.jsx";
|
|
3
|
+
import { UsingDirective } from "#components/UsingDirective.jsx";
|
|
1
4
|
import {
|
|
2
5
|
Block,
|
|
3
6
|
Children,
|
|
@@ -6,18 +9,19 @@ import {
|
|
|
6
9
|
Scope,
|
|
7
10
|
useBinder,
|
|
8
11
|
} from "@alloy-js/core";
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
CSharpFormatOptions,
|
|
14
|
+
useCsharpFormatOptions,
|
|
15
|
+
} from "../../contexts/format-options.js";
|
|
16
|
+
import { getGlobalNamespace } from "../../contexts/global-namespace.js";
|
|
17
|
+
import { useNamespaceContext } from "../../contexts/namespace.js";
|
|
18
|
+
import { CSharpSourceFileScope } from "../../scopes/source-file.js";
|
|
19
|
+
import { NamespaceSymbol } from "../../symbols/namespace.js";
|
|
16
20
|
|
|
17
21
|
/**
|
|
18
22
|
* Props for {@link SourceFile} component
|
|
19
23
|
*/
|
|
20
|
-
export interface SourceFileProps {
|
|
24
|
+
export interface SourceFileProps extends CSharpFormatOptions {
|
|
21
25
|
/** Path of the source file */
|
|
22
26
|
path: string;
|
|
23
27
|
|
|
@@ -48,13 +52,19 @@ export function SourceFile(props: SourceFileProps) {
|
|
|
48
52
|
const content = computed(() => (
|
|
49
53
|
<NamespaceScopes symbol={nsSymbol}>{props.children}</NamespaceScopes>
|
|
50
54
|
));
|
|
55
|
+
|
|
56
|
+
const opts = useCsharpFormatOptions({
|
|
57
|
+
printWidth: props.printWidth,
|
|
58
|
+
tabWidth: props.tabWidth,
|
|
59
|
+
useTabs: props.useTabs,
|
|
60
|
+
});
|
|
61
|
+
|
|
51
62
|
return (
|
|
52
63
|
<CoreSourceFile
|
|
53
64
|
path={props.path}
|
|
54
65
|
filetype="cs"
|
|
55
66
|
reference={Reference}
|
|
56
|
-
|
|
57
|
-
printWidth={120}
|
|
67
|
+
{...opts}
|
|
58
68
|
>
|
|
59
69
|
<Scope value={sourceFileScope}>
|
|
60
70
|
{(sourceFileScope.usings.size > 0 ||
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CommonFormatOptions,
|
|
3
|
+
createFormatOptionsContextFor,
|
|
4
|
+
} from "@alloy-js/core";
|
|
5
|
+
|
|
6
|
+
export interface CSharpFormatOptions extends CommonFormatOptions {}
|
|
7
|
+
|
|
8
|
+
export const {
|
|
9
|
+
Provider: CSharpFormatOptions,
|
|
10
|
+
useFormatOptions: useCsharpFormatOptions,
|
|
11
|
+
} = createFormatOptionsContextFor<CSharpFormatOptions>("csharp", {
|
|
12
|
+
tabWidth: 4,
|
|
13
|
+
printWidth: 120,
|
|
14
|
+
});
|