@alloy-js/csharp 0.18.0-dev.9 → 0.19.0-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/src/components/ClassDeclaration.d.ts +39 -2
  3. package/dist/src/components/ClassDeclaration.d.ts.map +1 -1
  4. package/dist/src/components/ClassDeclaration.js +35 -34
  5. package/dist/src/components/ClassMethod.d.ts +33 -1
  6. package/dist/src/components/ClassMethod.d.ts.map +1 -1
  7. package/dist/src/components/ClassMethod.js +22 -7
  8. package/dist/src/components/SourceFile.d.ts.map +1 -1
  9. package/dist/src/components/SourceFile.js +1 -0
  10. package/dist/src/components/attributes/attributes.d.ts +39 -0
  11. package/dist/src/components/attributes/attributes.d.ts.map +1 -0
  12. package/dist/src/components/attributes/attributes.js +62 -0
  13. package/dist/src/components/attributes/attributes.test.d.ts +2 -0
  14. package/dist/src/components/attributes/attributes.test.d.ts.map +1 -0
  15. package/dist/src/components/attributes/attributes.test.js +75 -0
  16. package/dist/src/components/index.d.ts +7 -1
  17. package/dist/src/components/index.d.ts.map +1 -1
  18. package/dist/src/components/index.js +8 -2
  19. package/dist/src/components/interface/declaration.d.ts +32 -1
  20. package/dist/src/components/interface/declaration.d.ts.map +1 -1
  21. package/dist/src/components/interface/declaration.js +18 -25
  22. package/dist/src/components/interface/declaration.test.js +102 -0
  23. package/dist/src/components/interface/method.d.ts +33 -1
  24. package/dist/src/components/interface/method.d.ts.map +1 -1
  25. package/dist/src/components/interface/method.js +22 -7
  26. package/dist/src/components/interface/method.test.js +169 -0
  27. package/dist/src/components/interface/property.d.ts +36 -1
  28. package/dist/src/components/interface/property.d.ts.map +1 -1
  29. package/dist/src/components/interface/property.js +18 -4
  30. package/dist/src/components/interface/property.test.js +24 -0
  31. package/dist/src/components/parameters/parameters.d.ts +19 -0
  32. package/dist/src/components/parameters/parameters.d.ts.map +1 -0
  33. package/dist/src/components/parameters/parameters.js +43 -0
  34. package/dist/src/components/property/property.d.ts +80 -0
  35. package/dist/src/components/property/property.d.ts.map +1 -0
  36. package/dist/src/components/property/property.js +76 -0
  37. package/dist/src/components/property/property.test.d.ts +2 -0
  38. package/dist/src/components/property/property.test.d.ts.map +1 -0
  39. package/dist/src/components/property/property.test.js +242 -0
  40. package/dist/src/components/record/declaration.d.ts +35 -0
  41. package/dist/src/components/record/declaration.d.ts.map +1 -0
  42. package/dist/src/components/record/declaration.js +90 -0
  43. package/dist/src/components/record/declaration.test.d.ts +2 -0
  44. package/dist/src/components/record/declaration.test.d.ts.map +1 -0
  45. package/dist/src/components/record/declaration.test.js +94 -0
  46. package/dist/src/components/type-parameters/type-parameter-constraints.d.ts +8 -0
  47. package/dist/src/components/type-parameters/type-parameter-constraints.d.ts.map +1 -0
  48. package/dist/src/components/type-parameters/type-parameter-constraints.js +44 -0
  49. package/dist/src/components/type-parameters/type-parameter-constraints.test.d.ts +2 -0
  50. package/dist/src/components/type-parameters/type-parameter-constraints.test.d.ts.map +1 -0
  51. package/dist/src/components/type-parameters/type-parameter-constraints.test.js +67 -0
  52. package/dist/src/components/type-parameters/type-parameter.d.ts +20 -0
  53. package/dist/src/components/type-parameters/type-parameter.d.ts.map +1 -0
  54. package/dist/src/components/type-parameters/type-parameter.js +22 -0
  55. package/dist/src/components/type-parameters/type-parameters.d.ts +17 -0
  56. package/dist/src/components/type-parameters/type-parameters.d.ts.map +1 -0
  57. package/dist/src/components/type-parameters/type-parameters.js +54 -0
  58. package/dist/src/components/type-parameters/type-parameters.test.d.ts +2 -0
  59. package/dist/src/components/type-parameters/type-parameters.test.d.ts.map +1 -0
  60. package/dist/src/components/type-parameters/type-parameters.test.js +48 -0
  61. package/dist/src/components/var/declaration.d.ts +35 -0
  62. package/dist/src/components/var/declaration.d.ts.map +1 -0
  63. package/dist/src/components/var/declaration.js +40 -0
  64. package/dist/src/components/var/declaration.test.d.ts +2 -0
  65. package/dist/src/components/var/declaration.test.d.ts.map +1 -0
  66. package/dist/src/components/var/declaration.test.js +73 -0
  67. package/dist/src/name-policy.d.ts +1 -1
  68. package/dist/src/name-policy.d.ts.map +1 -1
  69. package/dist/src/name-policy.js +1 -0
  70. package/dist/test/class-declaration.test.d.ts +2 -0
  71. package/dist/test/class-declaration.test.d.ts.map +1 -0
  72. package/dist/test/{class.test.js → class-declaration.test.js} +161 -33
  73. package/dist/test/project-directory.test.d.ts +2 -0
  74. package/dist/test/project-directory.test.d.ts.map +1 -0
  75. package/dist/tsconfig.tsbuildinfo +1 -1
  76. package/package.json +3 -3
  77. package/src/components/ClassDeclaration.tsx +65 -33
  78. package/src/components/ClassMethod.tsx +46 -4
  79. package/src/components/SourceFile.tsx +1 -0
  80. package/src/components/attributes/attributes.test.tsx +61 -0
  81. package/src/components/attributes/attributes.tsx +100 -0
  82. package/src/components/index.ts +7 -1
  83. package/src/components/interface/declaration.test.tsx +102 -0
  84. package/src/components/interface/declaration.tsx +43 -27
  85. package/src/components/interface/method.test.tsx +173 -0
  86. package/src/components/interface/method.tsx +45 -5
  87. package/src/components/interface/property.test.tsx +21 -0
  88. package/src/components/interface/property.tsx +43 -6
  89. package/src/components/parameters/parameters.tsx +74 -0
  90. package/src/components/property/property.test.tsx +209 -0
  91. package/src/components/property/property.tsx +172 -0
  92. package/src/components/record/declaration.test.tsx +73 -0
  93. package/src/components/record/declaration.tsx +109 -0
  94. package/src/components/type-parameters/type-parameter-constraints.test.tsx +93 -0
  95. package/src/components/type-parameters/type-parameter-constraints.tsx +46 -0
  96. package/src/components/type-parameters/type-parameter.tsx +35 -0
  97. package/src/components/type-parameters/type-parameters.test.tsx +46 -0
  98. package/src/components/type-parameters/type-parameters.tsx +63 -0
  99. package/src/components/var/declaration.test.tsx +59 -0
  100. package/src/components/var/declaration.tsx +47 -0
  101. package/src/name-policy.ts +3 -0
  102. package/temp/api.json +4722 -2384
  103. package/test/{class.test.tsx → class-declaration.test.tsx} +144 -26
  104. package/dist/src/components/Parameters.d.ts +0 -13
  105. package/dist/src/components/Parameters.d.ts.map +0 -1
  106. package/dist/src/components/Parameters.js +0 -34
  107. package/dist/test/class.test.d.ts +0 -2
  108. package/dist/test/class.test.d.ts.map +0 -1
  109. package/dist/test/projectdirectory.test.d.ts +0 -2
  110. package/dist/test/projectdirectory.test.d.ts.map +0 -1
  111. package/src/components/Parameters.tsx +0 -51
  112. /package/dist/test/{projectdirectory.test.js → project-directory.test.js} +0 -0
  113. /package/test/{projectdirectory.test.tsx → project-directory.test.tsx} +0 -0
@@ -1,4 +1,5 @@
1
1
  import * as core from "@alloy-js/core";
2
+ import { join } from "@alloy-js/core";
2
3
  import {
3
4
  AccessModifiers,
4
5
  computeModifiersPrefix,
@@ -8,9 +9,13 @@ import {
8
9
  import { CSharpElements, useCSharpNamePolicy } from "../name-policy.js";
9
10
  import { CSharpOutputSymbol } from "../symbols/csharp-output-symbol.js";
10
11
  import { CSharpMemberScope, useCSharpScope } from "../symbols/scopes.js";
11
- import { Name } from "./Name.jsx";
12
- import { ParameterProps, Parameters } from "./Parameters.jsx";
12
+ import { AttributeList, AttributesProp } from "./attributes/attributes.jsx";
13
13
  import { DocWhen } from "./doc/comment.jsx";
14
+ import { Name } from "./Name.jsx";
15
+ import { ParameterProps, Parameters } from "./parameters/parameters.jsx";
16
+ import { TypeParameterConstraints } from "./type-parameters/type-parameter-constraints.jsx";
17
+ import { TypeParameterProps } from "./type-parameters/type-parameter.jsx";
18
+ import { TypeParameters } from "./type-parameters/type-parameters.jsx";
14
19
 
15
20
  export interface ClassModifiers {
16
21
  readonly abstract?: boolean;
@@ -35,7 +40,44 @@ export interface ClassDeclarationProps
35
40
  /** Doc comment */
36
41
  doc?: core.Children;
37
42
  refkey?: core.Refkey;
38
- typeParameters?: Record<string, core.Refkey>;
43
+
44
+ /**
45
+ * Type parameters for the class
46
+ *
47
+ * @example
48
+ * ```tsx
49
+ * <ClassDeclaration name="MyClass" typeParameters={["T"]} />
50
+ * ```
51
+ * This will produce:
52
+ * ```csharp
53
+ * public class MyClass<T>
54
+ * ```
55
+ */
56
+ typeParameters?: (string | TypeParameterProps)[];
57
+
58
+ /** Base class that this class extends */
59
+ baseType?: core.Children;
60
+
61
+ /** Interfaces this class implements */
62
+ interfaceTypes?: core.Children[];
63
+
64
+ /**
65
+ * Define attributes to attach
66
+ * @example
67
+ * ```tsx
68
+ * <ClassDeclaration name="MyClass" attributes={[
69
+ * <Attribute name="Test" />
70
+ * <Attribute name="Test2" args={["arg1", "arg2"]} />
71
+ * ]}>
72
+ * ```
73
+ * This will produce:
74
+ * ```csharp
75
+ * [Test]
76
+ * [Test2("arg1", "arg2")]
77
+ * public class MyClass
78
+ * ```
79
+ */
80
+ attributes?: AttributesProp;
39
81
  }
40
82
 
41
83
  /**
@@ -77,31 +119,12 @@ export function ClassDeclaration(props: ClassDeclarationProps) {
77
119
  owner: thisClassSymbol,
78
120
  });
79
121
 
80
- let typeParams: core.Children;
81
- if (props.typeParameters) {
82
- const typeParamNames = new Array<string>();
83
- for (const entry of Object.entries(props.typeParameters)) {
84
- typeParamNames.push(
85
- useCSharpNamePolicy().getName(entry[0], "type-parameter"),
86
- );
87
- // create a symbol for each type param so its
88
- // refkey resolves to the type param's name
89
- new CSharpOutputSymbol(entry[0], {
90
- scope: thisClassScope,
91
- refkeys: entry[1],
92
- });
93
- }
94
- typeParams = (
95
- <group>
96
- {"<"}
97
- <core.For each={typeParamNames} comma line>
98
- {(name) => name}
99
- </core.For>
100
- {">"}
101
- </group>
102
- );
103
- }
104
-
122
+ const bases = [
123
+ ...(props.baseType ? [props.baseType] : []),
124
+ ...(props.interfaceTypes || []),
125
+ ];
126
+ const base =
127
+ bases.length > 0 ? <> : {join(bases, { joiner: ", " })}</> : null;
105
128
  const modifiers = computeModifiersPrefix([
106
129
  getAccessModifier(props),
107
130
  getClassModifiers(props),
@@ -109,8 +132,15 @@ export function ClassDeclaration(props: ClassDeclarationProps) {
109
132
  return (
110
133
  <core.Declaration symbol={thisClassSymbol}>
111
134
  <DocWhen doc={props.doc} />
135
+ <AttributeList attributes={props.attributes} endline />
112
136
  {modifiers}class <Name />
113
- {typeParams}
137
+ {props.typeParameters && (
138
+ <TypeParameters parameters={props.typeParameters} />
139
+ )}
140
+ {base}
141
+ {props.typeParameters && (
142
+ <TypeParameterConstraints parameters={props.typeParameters} />
143
+ )}
114
144
  {!props.children && ";"}
115
145
  {props.children && (
116
146
  <core.Block newline>
@@ -151,15 +181,14 @@ export function ClassConstructor(props: ClassConstructorProps) {
151
181
 
152
182
  const modifiers = computeModifiersPrefix([getAccessModifier(props)]);
153
183
 
154
- const params =
155
- props.parameters ? <Parameters parameters={props.parameters} /> : "";
156
-
157
184
  // note that scope wraps the ctor decl so that the params get the correct scope
158
185
  return (
159
186
  <core.Declaration symbol={ctorSymbol}>
160
187
  <core.Scope value={ctorDeclScope}>
161
188
  {modifiers}
162
- <Name />({params})<core.Block newline>{props.children}</core.Block>
189
+ <Name />
190
+ <Parameters parameters={props.parameters} />
191
+ <core.Block newline>{props.children}</core.Block>
163
192
  </core.Scope>
164
193
  </core.Declaration>
165
194
  );
@@ -170,6 +199,8 @@ export interface ClassMemberProps extends AccessModifiers {
170
199
  name: string;
171
200
  type: core.Children;
172
201
  refkey?: core.Refkey;
202
+ /** Doc comment */
203
+ doc?: core.Children;
173
204
  }
174
205
 
175
206
  // a C# class member (i.e. a field within a class like "private int count")
@@ -194,6 +225,7 @@ export function ClassMember(props: ClassMemberProps) {
194
225
  const modifiers = computeModifiersPrefix([getAccessModifier(props)]);
195
226
  return (
196
227
  <core.Declaration symbol={memberSymbol}>
228
+ <DocWhen doc={props.doc} />
197
229
  {modifiers}
198
230
  {props.type} <Name />
199
231
  </core.Declaration>
@@ -16,8 +16,12 @@ import {
16
16
  import { useCSharpNamePolicy } from "../name-policy.js";
17
17
  import { CSharpOutputSymbol } from "../symbols/csharp-output-symbol.js";
18
18
  import { CSharpMemberScope, useCSharpScope } from "../symbols/scopes.js";
19
- import { ParameterProps, Parameters } from "./Parameters.jsx";
19
+ import { AttributeList, AttributesProp } from "./attributes/attributes.jsx";
20
20
  import { DocWhen } from "./doc/comment.jsx";
21
+ import { ParameterProps, Parameters } from "./parameters/parameters.jsx";
22
+ import { TypeParameterConstraints } from "./type-parameters/type-parameter-constraints.jsx";
23
+ import { TypeParameterProps } from "./type-parameters/type-parameter.jsx";
24
+ import { TypeParameters } from "./type-parameters/type-parameters.jsx";
21
25
 
22
26
  /** Method modifiers. Can only be one. */
23
27
  export interface ClassMethodModifiers {
@@ -51,6 +55,38 @@ export interface ClassMethodProps
51
55
 
52
56
  /** Doc comment */
53
57
  doc?: Children;
58
+
59
+ /**
60
+ * Type parameters for the method
61
+ *
62
+ * @example
63
+ * ```tsx
64
+ * <InterfaceMethod name="Test" typeParameters={["T"]} />
65
+ * ```
66
+ * This will produce:
67
+ * ```csharp
68
+ * public void Test<T>()
69
+ * ```
70
+ */
71
+ typeParameters?: (TypeParameterProps | string)[];
72
+
73
+ /**
74
+ * Define attributes to attach
75
+ * @example
76
+ * ```tsx
77
+ * <ClassMethod name="MyMethod" attributes={[
78
+ * <Attribute name="Test" />
79
+ * <Attribute name="Test2" args={["arg1", "arg2"]} />
80
+ * ]} />
81
+ * ```
82
+ * This will produce:
83
+ * ```csharp
84
+ * [Test]
85
+ * [Test2("arg1", "arg2")]
86
+ * public void MyMethod() { }
87
+ * ```
88
+ */
89
+ attributes?: AttributesProp;
54
90
  }
55
91
 
56
92
  // a C# class method
@@ -71,8 +107,6 @@ export function ClassMethod(props: ClassMethodProps) {
71
107
  owner: methodSymbol,
72
108
  });
73
109
 
74
- const params =
75
- props.parameters ? <Parameters parameters={props.parameters} /> : "";
76
110
  const returns = props.returns ?? (props.async ? "Task" : "void");
77
111
 
78
112
  const modifiers = computeModifiersPrefix([
@@ -85,8 +119,16 @@ export function ClassMethod(props: ClassMethodProps) {
85
119
  <MemberDeclaration symbol={methodSymbol}>
86
120
  <Scope value={methodScope}>
87
121
  <DocWhen doc={props.doc} />
122
+ <AttributeList attributes={props.attributes} endline />
88
123
  {modifiers}
89
- {returns} {name}({params})
124
+ {returns} {name}
125
+ {props.typeParameters && (
126
+ <TypeParameters parameters={props.typeParameters} />
127
+ )}
128
+ <Parameters parameters={props.parameters} />
129
+ {props.typeParameters && (
130
+ <TypeParameterConstraints parameters={props.typeParameters} />
131
+ )}
90
132
  {props.abstract ? ";" : <Block newline>{props.children}</Block>}
91
133
  </Scope>
92
134
  </MemberDeclaration>
@@ -58,6 +58,7 @@ export function SourceFile(props: SourceFileProps) {
58
58
  filetype="cs"
59
59
  reference={Reference}
60
60
  tabWidth={4}
61
+ printWidth={120}
61
62
  >
62
63
  <SourceFileContext.Provider value={sourceFileCtx}>
63
64
  <core.Scope name={props.path} kind="source-file">
@@ -0,0 +1,61 @@
1
+ import { expect, it } from "vitest";
2
+ import { Attribute, AttributeList } from "./attributes.jsx";
3
+
4
+ it("define attribute", () => {
5
+ expect(<Attribute name="Test" />).toRenderTo(`
6
+ [Test]
7
+ `);
8
+ });
9
+
10
+ it("define attribute with single arg", () => {
11
+ expect(<Attribute name="Test" args={[`"abc"`]} />).toRenderTo(`
12
+ [Test("abc")]
13
+ `);
14
+ });
15
+
16
+ it("define attribute with multiple arg", () => {
17
+ expect(<Attribute name="Test" args={[`"abc"`, `"def"`]} />).toRenderTo(`
18
+ [Test("abc", "def")]
19
+ `);
20
+ });
21
+
22
+ it("define attribute list with Attribute components", () => {
23
+ expect(
24
+ <AttributeList
25
+ attributes={[<Attribute name="TestA" />, <Attribute name="TestB" />]}
26
+ />,
27
+ ).toRenderTo(`
28
+ [TestA]
29
+ [TestB]
30
+ `);
31
+ });
32
+
33
+ it("define attribute list with attribute names", () => {
34
+ expect(<AttributeList attributes={["TestA", "TestB"]} />).toRenderTo(`
35
+ [TestA]
36
+ [TestB]
37
+ `);
38
+ });
39
+
40
+ it("define attribute list with attribute props", () => {
41
+ expect(
42
+ <AttributeList
43
+ attributes={[{ name: "TestA" }, { name: "TestB", args: [`"test"`] }]}
44
+ />,
45
+ ).toRenderTo(`
46
+ [TestA]
47
+ [TestB("test")]
48
+ `);
49
+ });
50
+
51
+ it("define attribute list with children", () => {
52
+ expect(
53
+ <AttributeList>
54
+ <Attribute name="TestA" />
55
+ <Attribute name="TestB" />
56
+ </AttributeList>,
57
+ ).toRenderTo(`
58
+ [TestA]
59
+ [TestB]
60
+ `);
61
+ });
@@ -0,0 +1,100 @@
1
+ import {
2
+ Children,
3
+ findKeyedChildren,
4
+ For,
5
+ Indent,
6
+ taggedComponent,
7
+ } from "@alloy-js/core";
8
+
9
+ export interface AttributeItem {
10
+ name: string;
11
+ args?: string[];
12
+ }
13
+
14
+ export type AttributesProp = Array<string | AttributeProps | Children>;
15
+
16
+ export interface AttributeListProps {
17
+ /** If the attribute list should finish with a hard line if there is any attribute */
18
+ endline?: boolean;
19
+ attributes?: AttributesProp;
20
+ children?: Children[];
21
+ }
22
+
23
+ /**
24
+ * Render each attributes in a new line.
25
+ */
26
+ export function AttributeList(props: AttributeListProps) {
27
+ const attributes =
28
+ props.attributes ??
29
+ (props.children && findKeyedChildren(props.children, Attribute.tag));
30
+
31
+ if (!attributes) {
32
+ return null;
33
+ }
34
+
35
+ return (
36
+ <>
37
+ <For each={attributes} line>
38
+ {(arg) => renderAttribute(arg)}
39
+ </For>
40
+ {props.endline && attributes.length > 0 && <hbr />}
41
+ </>
42
+ );
43
+ }
44
+
45
+ function renderAttribute(attr: string | AttributeProps | Children): Children {
46
+ if (typeof attr === "string") {
47
+ return <Attribute name={attr} />;
48
+ } else if (typeof attr === "object" && attr && "name" in attr) {
49
+ return <Attribute {...attr} />;
50
+ } else {
51
+ return attr;
52
+ }
53
+ }
54
+
55
+ export interface AttributeProps {
56
+ /** Attribute name */
57
+ name: Children;
58
+
59
+ /** Argument */
60
+ args?: Children[];
61
+ }
62
+
63
+ const AttributeTag = Symbol("AttributeTag");
64
+ /**
65
+ * Render a csharp attribute.
66
+ *
67
+ * @example
68
+ * ```tsx
69
+ * <Attribute name="Test" /><hbr/>
70
+ * <Attribute name="Test" args={["arg1", "arg2"]} />
71
+ * ```
72
+ *
73
+ * will render:
74
+ * ```csharp
75
+ * [Test]
76
+ * [Test("arg1", "arg2")]
77
+ * ```
78
+ */
79
+ export const Attribute = taggedComponent(
80
+ AttributeTag,
81
+ (props: AttributeProps) => {
82
+ return (
83
+ <group>
84
+ [{props.name}
85
+ {props.args && props.args.length > 0 && (
86
+ <>
87
+ (
88
+ <Indent softline>
89
+ <For each={props.args ?? []} comma line>
90
+ {(arg) => arg}
91
+ </For>
92
+ </Indent>
93
+ )
94
+ </>
95
+ )}
96
+ ]
97
+ </group>
98
+ );
99
+ },
100
+ );
@@ -1,3 +1,4 @@
1
+ export * from "./attributes/attributes.jsx";
1
2
  export * from "./ClassDeclaration.jsx";
2
3
  export * from "./ClassMethod.jsx";
3
4
  export * from "./Declaration.js";
@@ -6,10 +7,15 @@ export * from "./doc/from-markdown.jsx";
6
7
  export * from "./EnumDeclaration.jsx";
7
8
  export * from "./interface/declaration.js";
8
9
  export * from "./interface/method.js";
10
+ export * from "./interface/property.js";
9
11
  export * from "./Name.js";
10
12
  export * from "./Namespace.js";
11
- export * from "./Parameters.js";
13
+ export * from "./parameters/parameters.jsx";
12
14
  export * from "./ProjectDirectory.js";
15
+ export * from "./property/property.jsx";
16
+ export * from "./record/declaration.js";
13
17
  export * from "./Reference.js";
14
18
  export * from "./SourceFile.js";
19
+ export type { TypeParameterProps } from "./type-parameters/type-parameter.jsx";
15
20
  export * from "./UsingDirective.js";
21
+ export * from "./var/declaration.jsx";
@@ -1,6 +1,11 @@
1
+ import { List, refkey } from "@alloy-js/core";
1
2
  import { describe, expect, it } from "vitest";
2
3
  import { TestNamespace } from "../../../test/utils.jsx";
4
+ import { Attribute } from "../attributes/attributes.jsx";
5
+ import { SourceFile } from "../SourceFile.jsx";
6
+ import { TypeParameterProps } from "../type-parameters/type-parameter.jsx";
3
7
  import { InterfaceDeclaration } from "./declaration.jsx";
8
+ import { InterfaceProperty } from "./property.jsx";
4
9
 
5
10
  it("declares class with no members", () => {
6
11
  expect(
@@ -54,3 +59,100 @@ it("specify doc comment", () => {
54
59
  interface TestInterface;
55
60
  `);
56
61
  });
62
+
63
+ describe("with type parameters", () => {
64
+ it("reference parameters", () => {
65
+ const typeParameters: TypeParameterProps[] = [
66
+ {
67
+ name: "T",
68
+ refkey: refkey(),
69
+ },
70
+ {
71
+ name: "U",
72
+ refkey: refkey(),
73
+ },
74
+ ];
75
+
76
+ expect(
77
+ <TestNamespace>
78
+ <SourceFile path="Test.cs">
79
+ <InterfaceDeclaration
80
+ public
81
+ name="Test"
82
+ typeParameters={typeParameters}
83
+ >
84
+ <List>
85
+ <InterfaceProperty
86
+ name="PropA"
87
+ type={typeParameters[0].refkey}
88
+ get
89
+ set
90
+ />
91
+ <InterfaceProperty
92
+ name="PropB"
93
+ type={typeParameters[1].refkey}
94
+ get
95
+ set
96
+ />
97
+ </List>
98
+ </InterfaceDeclaration>
99
+ </SourceFile>
100
+ </TestNamespace>,
101
+ ).toRenderTo(`
102
+ namespace TestCode
103
+ {
104
+ public interface Test<T, U>
105
+ {
106
+ T PropA { get; set; }
107
+ U PropB { get; set; }
108
+ }
109
+ }
110
+ `);
111
+ });
112
+
113
+ it("defines with constraints", () => {
114
+ const typeParameters: TypeParameterProps[] = [
115
+ {
116
+ name: "T",
117
+ constraints: "IFoo",
118
+ },
119
+ {
120
+ name: "U",
121
+ constraints: "IBar",
122
+ },
123
+ ];
124
+
125
+ expect(
126
+ <TestNamespace>
127
+ <InterfaceDeclaration
128
+ public
129
+ name="Test"
130
+ typeParameters={typeParameters}
131
+ >
132
+ // Body
133
+ </InterfaceDeclaration>
134
+ </TestNamespace>,
135
+ ).toRenderTo(`
136
+ public interface Test<T, U>
137
+ where T : IFoo
138
+ where U : IBar
139
+ {
140
+ // Body
141
+ }
142
+ `);
143
+ });
144
+ });
145
+
146
+ it("specify attributes", () => {
147
+ expect(
148
+ <TestNamespace>
149
+ <InterfaceDeclaration
150
+ name="Test"
151
+ attributes={[<Attribute name="Test" />]}
152
+ />
153
+ </TestNamespace>,
154
+ ).toRenderTo(`
155
+ [Test]
156
+ interface Test;
157
+ `);
158
+ });
@@ -8,8 +8,12 @@ import {
8
8
  import { useCSharpNamePolicy } from "../../name-policy.js";
9
9
  import { CSharpOutputSymbol } from "../../symbols/csharp-output-symbol.js";
10
10
  import { CSharpMemberScope } from "../../symbols/scopes.js";
11
+ import { AttributeList, AttributesProp } from "../attributes/attributes.jsx";
11
12
  import { DocWhen } from "../doc/comment.jsx";
12
13
  import { Name } from "../Name.jsx";
14
+ import { TypeParameterConstraints } from "../type-parameters/type-parameter-constraints.jsx";
15
+ import { TypeParameterProps } from "../type-parameters/type-parameter.jsx";
16
+ import { TypeParameters } from "../type-parameters/type-parameters.jsx";
13
17
 
14
18
  export interface InterfaceModifiers {
15
19
  readonly partial?: boolean;
@@ -27,7 +31,38 @@ export interface InterfaceDeclarationProps
27
31
  /** Doc comment */
28
32
  doc?: core.Children;
29
33
  refkey?: core.Refkey;
30
- typeParameters?: Record<string, core.Refkey>;
34
+
35
+ /**
36
+ * Type parameters for the interface
37
+ *
38
+ * @example
39
+ * ```tsx
40
+ * <InterfaceDeclaration name="IList" typeParameters={["T"]} />
41
+ * ```
42
+ * This will produce:
43
+ * ```csharp
44
+ * public interface IList<T>
45
+ * ```
46
+ */
47
+ typeParameters?: (TypeParameterProps | string)[];
48
+
49
+ /**
50
+ * Define attributes to attach
51
+ * @example
52
+ * ```tsx
53
+ * <InterfaceDeclaration name="MyInterface" attributes={[
54
+ * <Attribute name="Test" />
55
+ * <Attribute name="Test2" args={["arg1", "arg2"]} />
56
+ * ]} />
57
+ * ```
58
+ * This will produce:
59
+ * ```csharp
60
+ * [Test]
61
+ * [Test2("arg1", "arg2")]
62
+ * public interface MyInterface
63
+ * ```
64
+ */
65
+ attributes?: AttributesProp;
31
66
  }
32
67
 
33
68
  /**
@@ -65,31 +100,6 @@ export function InterfaceDeclaration(props: InterfaceDeclarationProps) {
65
100
  owner: thisInterfaceSymbol,
66
101
  });
67
102
 
68
- let typeParams: core.Children;
69
- if (props.typeParameters) {
70
- const typeParamNames = new Array<string>();
71
- for (const entry of Object.entries(props.typeParameters)) {
72
- typeParamNames.push(
73
- useCSharpNamePolicy().getName(entry[0], "type-parameter"),
74
- );
75
- // create a symbol for each type param so its
76
- // refkey resolves to the type param's name
77
- new CSharpOutputSymbol(entry[0], {
78
- scope: thisInterfaceScope,
79
- refkeys: entry[1],
80
- });
81
- }
82
- typeParams = (
83
- <group>
84
- {"<"}
85
- <core.For each={typeParamNames} comma line>
86
- {(name) => name}
87
- </core.For>
88
- {">"}
89
- </group>
90
- );
91
- }
92
-
93
103
  const modifiers = computeModifiersPrefix([
94
104
  getAccessModifier(props),
95
105
  getInterfaceModifiers(props),
@@ -97,8 +107,14 @@ export function InterfaceDeclaration(props: InterfaceDeclarationProps) {
97
107
  return (
98
108
  <core.Declaration symbol={thisInterfaceSymbol}>
99
109
  <DocWhen doc={props.doc} />
110
+ <AttributeList attributes={props.attributes} endline />
100
111
  {modifiers}interface <Name />
101
- {typeParams}
112
+ {props.typeParameters && (
113
+ <TypeParameters parameters={props.typeParameters} />
114
+ )}
115
+ {props.typeParameters && (
116
+ <TypeParameterConstraints parameters={props.typeParameters} />
117
+ )}
102
118
  {props.children ?
103
119
  <core.Block newline>
104
120
  <core.Scope value={thisInterfaceScope}>{props.children}</core.Scope>