@alloy-js/csharp 0.18.0-dev.8 → 0.18.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 (127) 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/doc/comment.d.ts +12 -11
  17. package/dist/src/components/doc/comment.d.ts.map +1 -1
  18. package/dist/src/components/doc/comment.js +27 -10
  19. package/dist/src/components/doc/comment.test.js +98 -88
  20. package/dist/src/components/doc/from-markdown.d.ts +6 -0
  21. package/dist/src/components/doc/from-markdown.d.ts.map +1 -0
  22. package/dist/src/components/doc/from-markdown.js +58 -0
  23. package/dist/src/components/doc/from-markdown.test.d.ts +2 -0
  24. package/dist/src/components/doc/from-markdown.test.d.ts.map +1 -0
  25. package/dist/src/components/doc/from-markdown.test.js +83 -0
  26. package/dist/src/components/index.d.ts +9 -1
  27. package/dist/src/components/index.d.ts.map +1 -1
  28. package/dist/src/components/index.js +10 -2
  29. package/dist/src/components/interface/declaration.d.ts +32 -1
  30. package/dist/src/components/interface/declaration.d.ts.map +1 -1
  31. package/dist/src/components/interface/declaration.js +18 -25
  32. package/dist/src/components/interface/declaration.test.js +102 -0
  33. package/dist/src/components/interface/method.d.ts +33 -1
  34. package/dist/src/components/interface/method.d.ts.map +1 -1
  35. package/dist/src/components/interface/method.js +22 -7
  36. package/dist/src/components/interface/method.test.js +169 -0
  37. package/dist/src/components/interface/property.d.ts +36 -1
  38. package/dist/src/components/interface/property.d.ts.map +1 -1
  39. package/dist/src/components/interface/property.js +18 -4
  40. package/dist/src/components/interface/property.test.js +24 -0
  41. package/dist/src/components/parameters/parameters.d.ts +19 -0
  42. package/dist/src/components/parameters/parameters.d.ts.map +1 -0
  43. package/dist/src/components/parameters/parameters.js +43 -0
  44. package/dist/src/components/property/property.d.ts +80 -0
  45. package/dist/src/components/property/property.d.ts.map +1 -0
  46. package/dist/src/components/property/property.js +76 -0
  47. package/dist/src/components/property/property.test.d.ts +2 -0
  48. package/dist/src/components/property/property.test.d.ts.map +1 -0
  49. package/dist/src/components/property/property.test.js +242 -0
  50. package/dist/src/components/record/declaration.d.ts +35 -0
  51. package/dist/src/components/record/declaration.d.ts.map +1 -0
  52. package/dist/src/components/record/declaration.js +90 -0
  53. package/dist/src/components/record/declaration.test.d.ts +2 -0
  54. package/dist/src/components/record/declaration.test.d.ts.map +1 -0
  55. package/dist/src/components/record/declaration.test.js +94 -0
  56. package/dist/src/components/type-parameters/type-parameter-constraints.d.ts +8 -0
  57. package/dist/src/components/type-parameters/type-parameter-constraints.d.ts.map +1 -0
  58. package/dist/src/components/type-parameters/type-parameter-constraints.js +44 -0
  59. package/dist/src/components/type-parameters/type-parameter-constraints.test.d.ts +2 -0
  60. package/dist/src/components/type-parameters/type-parameter-constraints.test.d.ts.map +1 -0
  61. package/dist/src/components/type-parameters/type-parameter-constraints.test.js +67 -0
  62. package/dist/src/components/type-parameters/type-parameter.d.ts +20 -0
  63. package/dist/src/components/type-parameters/type-parameter.d.ts.map +1 -0
  64. package/dist/src/components/type-parameters/type-parameter.js +22 -0
  65. package/dist/src/components/type-parameters/type-parameters.d.ts +17 -0
  66. package/dist/src/components/type-parameters/type-parameters.d.ts.map +1 -0
  67. package/dist/src/components/type-parameters/type-parameters.js +54 -0
  68. package/dist/src/components/type-parameters/type-parameters.test.d.ts +2 -0
  69. package/dist/src/components/type-parameters/type-parameters.test.d.ts.map +1 -0
  70. package/dist/src/components/type-parameters/type-parameters.test.js +48 -0
  71. package/dist/src/components/var/declaration.d.ts +35 -0
  72. package/dist/src/components/var/declaration.d.ts.map +1 -0
  73. package/dist/src/components/var/declaration.js +40 -0
  74. package/dist/src/components/var/declaration.test.d.ts +2 -0
  75. package/dist/src/components/var/declaration.test.d.ts.map +1 -0
  76. package/dist/src/components/var/declaration.test.js +73 -0
  77. package/dist/src/name-policy.d.ts +1 -1
  78. package/dist/src/name-policy.d.ts.map +1 -1
  79. package/dist/src/name-policy.js +1 -0
  80. package/dist/test/class-declaration.test.d.ts +2 -0
  81. package/dist/test/class-declaration.test.d.ts.map +1 -0
  82. package/dist/test/{class.test.js → class-declaration.test.js} +161 -33
  83. package/dist/test/project-directory.test.d.ts +2 -0
  84. package/dist/test/project-directory.test.d.ts.map +1 -0
  85. package/dist/tsconfig.tsbuildinfo +1 -1
  86. package/package.json +7 -6
  87. package/src/components/ClassDeclaration.tsx +65 -33
  88. package/src/components/ClassMethod.tsx +46 -4
  89. package/src/components/SourceFile.tsx +1 -0
  90. package/src/components/attributes/attributes.test.tsx +61 -0
  91. package/src/components/attributes/attributes.tsx +100 -0
  92. package/src/components/doc/comment.test.tsx +80 -79
  93. package/src/components/doc/comment.tsx +44 -14
  94. package/src/components/doc/from-markdown.test.tsx +103 -0
  95. package/src/components/doc/from-markdown.tsx +58 -0
  96. package/src/components/index.ts +9 -1
  97. package/src/components/interface/declaration.test.tsx +102 -0
  98. package/src/components/interface/declaration.tsx +43 -27
  99. package/src/components/interface/method.test.tsx +173 -0
  100. package/src/components/interface/method.tsx +45 -5
  101. package/src/components/interface/property.test.tsx +21 -0
  102. package/src/components/interface/property.tsx +43 -6
  103. package/src/components/parameters/parameters.tsx +74 -0
  104. package/src/components/property/property.test.tsx +209 -0
  105. package/src/components/property/property.tsx +172 -0
  106. package/src/components/record/declaration.test.tsx +73 -0
  107. package/src/components/record/declaration.tsx +109 -0
  108. package/src/components/type-parameters/type-parameter-constraints.test.tsx +93 -0
  109. package/src/components/type-parameters/type-parameter-constraints.tsx +46 -0
  110. package/src/components/type-parameters/type-parameter.tsx +35 -0
  111. package/src/components/type-parameters/type-parameters.test.tsx +46 -0
  112. package/src/components/type-parameters/type-parameters.tsx +63 -0
  113. package/src/components/var/declaration.test.tsx +59 -0
  114. package/src/components/var/declaration.tsx +47 -0
  115. package/src/name-policy.ts +3 -0
  116. package/temp/api.json +5838 -1626
  117. package/test/{class.test.tsx → class-declaration.test.tsx} +144 -26
  118. package/dist/src/components/Parameters.d.ts +0 -13
  119. package/dist/src/components/Parameters.d.ts.map +0 -1
  120. package/dist/src/components/Parameters.js +0 -34
  121. package/dist/test/class.test.d.ts +0 -2
  122. package/dist/test/class.test.d.ts.map +0 -1
  123. package/dist/test/projectdirectory.test.d.ts +0 -2
  124. package/dist/test/projectdirectory.test.d.ts.map +0 -1
  125. package/src/components/Parameters.tsx +0 -51
  126. /package/dist/test/{projectdirectory.test.js → project-directory.test.js} +0 -0
  127. /package/test/{projectdirectory.test.tsx → project-directory.test.tsx} +0 -0
@@ -1,4 +1,4 @@
1
- import { Children, code, List, Prose, Show } from "@alloy-js/core";
1
+ import { Children, code, For, Indent, List, Prose, Show } from "@alloy-js/core";
2
2
 
3
3
  export interface DocCommentProps {
4
4
  children: Children;
@@ -53,7 +53,7 @@ export function makeInlineDocCommentTag(name: string) {
53
53
 
54
54
  export const DocSummary = makeDocCommentTag("summary");
55
55
  export const DocCode = makeDocCommentTag("code");
56
- export const DocC = makeDocCommentTag("c");
56
+ export const DocC = makeInlineDocCommentTag("c");
57
57
  export const DocExample = makeDocCommentTag("example");
58
58
  export const DocException = makeDocCommentTag("exception");
59
59
 
@@ -85,29 +85,40 @@ export const DocReturns = makeDocCommentTag("returns");
85
85
  export const DocRemarks = makeDocCommentTag("remarks");
86
86
  export const DocValue = makeDocCommentTag("value");
87
87
  export const DocPermission = makeDocCommentTag("permission");
88
- export const DocResponse = makeDocCommentTag("response");
89
- export const DocCompletionList = makeDocCommentTag("completionlist");
90
- export const DocList = makeDocCommentTag("list");
91
- export const DocItem = makeDocCommentTag("item");
92
- export const DocTerm = makeDocCommentTag("term");
93
88
  export const DocDescription = makeDocCommentTag("description");
94
89
  export const DocPara = makeDocCommentTag("para");
95
90
 
96
91
  export interface DocSeeProps {
97
- cref: string;
92
+ cref?: string;
93
+ href?: string;
98
94
  langword?: string;
99
95
  children?: Children;
100
96
  }
101
- export const DocSee = (props: DocSeeProps) =>
102
- `<see cref="${props.cref}"${props.langword ? ` langword="${props.langword}"` : ""}${props.children ? `>${props.children}</see>` : " />"}`;
97
+ export const DocSee = (props: DocSeeProps) => {
98
+ const attributes = [
99
+ props.cref ? `cref="${props.cref}"` : undefined,
100
+ props.href ? `href="${props.href}"` : undefined,
101
+ props.langword ? `langword="${props.langword}"` : undefined,
102
+ ]
103
+ .filter(Boolean)
104
+ .join(" ");
105
+ return code`<see ${attributes}${props.children ? code`>${props.children}</see>` : " />"}`;
106
+ };
103
107
 
104
108
  export interface DocSeeAlsoProps {
105
- cref: string;
106
- langword?: string;
109
+ cref?: string;
110
+ href?: string;
107
111
  children?: Children;
108
112
  }
109
- export const DocSeeAlso = (props: DocSeeAlsoProps) =>
110
- `<seealso cref="${props.cref}"${props.langword ? ` langword="${props.langword}"` : ""}${props.children ? `>${props.children}</seealso>` : " />"}`;
113
+ export const DocSeeAlso = (props: DocSeeAlsoProps) => {
114
+ const attributes = [
115
+ props.cref ? `cref="${props.cref}"` : undefined,
116
+ props.href ? `href="${props.href}"` : undefined,
117
+ ]
118
+ .filter(Boolean)
119
+ .join(" ");
120
+ return code`<seealso ${attributes}${props.children ? code`>${props.children}</seealso>` : " />"}`;
121
+ };
111
122
 
112
123
  export interface DocParamRefProps {
113
124
  name: string;
@@ -120,3 +131,22 @@ export interface DocTypeParamRefProps {
120
131
  }
121
132
  export const DocTypeParamRef = (props: DocTypeParamRefProps) =>
122
133
  `<typeparamref name="${props.name}" />`;
134
+
135
+ export interface DocListProps {
136
+ type?: "bullet" | "number";
137
+ items: Children[];
138
+ }
139
+ export function DocList(props: DocListProps) {
140
+ return (
141
+ <Prose>
142
+ {`<list type="${props.type ?? "bullet"}">`}
143
+ <Indent>
144
+ <For each={props.items}>
145
+ {(item) => code`<item><description>${item}</description></item>`}
146
+ </For>
147
+ </Indent>
148
+ <hbr />
149
+ {`</list>`}
150
+ </Prose>
151
+ );
152
+ }
@@ -0,0 +1,103 @@
1
+ import { d } from "@alloy-js/core/testing";
2
+ import { describe, expect, it } from "vitest";
3
+ import { DocFromMarkdown } from "./from-markdown.jsx";
4
+
5
+ it("convert code block to <code>", () => {
6
+ expect(
7
+ <DocFromMarkdown
8
+ markdown={d`
9
+ Some markdown with code
10
+ \`\`\`csharp
11
+ var foo = "bar";
12
+ \`\`\`
13
+ `}
14
+ />,
15
+ ).toRenderTo(`
16
+ Some markdown with code
17
+ <code>
18
+ var foo = "bar";
19
+ </code>
20
+ `);
21
+ });
22
+
23
+ it("convert inline code block to <c>", () => {
24
+ expect(
25
+ <DocFromMarkdown
26
+ markdown={d`
27
+ Some markdown with \`inline\` code
28
+ `}
29
+ />,
30
+ ).toRenderTo(`
31
+ Some markdown with <c>inline</c> code
32
+ `);
33
+ });
34
+
35
+ it("convert link to <see>", () => {
36
+ expect(
37
+ <DocFromMarkdown
38
+ markdown={d`
39
+ Some markdown with [link](https://example.com)
40
+ `}
41
+ />,
42
+ ).toRenderTo(`
43
+ Some markdown with <see href="https://example.com">link</see>
44
+ `);
45
+ });
46
+
47
+ it("convert bullet list to <list>", () => {
48
+ expect(
49
+ <DocFromMarkdown
50
+ markdown={d`
51
+ - Item 1
52
+ - Item 2
53
+ - Item 3
54
+ `}
55
+ />,
56
+ ).toRenderTo(`
57
+ <list type="bullet">
58
+ <item><description>Item 1</description></item>
59
+ <item><description>Item 2</description></item>
60
+ <item><description>Item 3</description></item>
61
+ </list>
62
+ `);
63
+ });
64
+
65
+ it("convert numbered list to <list>", () => {
66
+ expect(
67
+ <DocFromMarkdown
68
+ markdown={d`
69
+ 1. Item 1
70
+ 2. Item 2
71
+ 3. Item 3
72
+ `}
73
+ />,
74
+ ).toRenderTo(`
75
+ <list type="number">
76
+ <item><description>Item 1</description></item>
77
+ <item><description>Item 2</description></item>
78
+ <item><description>Item 3</description></item>
79
+ </list>
80
+ `);
81
+ });
82
+
83
+ describe("strip unsupported elements", () => {
84
+ it("bold", () => {
85
+ expect(
86
+ <DocFromMarkdown
87
+ markdown={d`
88
+ Some markdown with **bold** text
89
+ `}
90
+ />,
91
+ ).toRenderTo(`Some markdown with bold text`);
92
+ });
93
+
94
+ it("italic", () => {
95
+ expect(
96
+ <DocFromMarkdown
97
+ markdown={d`
98
+ Some markdown with *italic* text
99
+ `}
100
+ />,
101
+ ).toRenderTo(`Some markdown with italic text`);
102
+ });
103
+ });
@@ -0,0 +1,58 @@
1
+ import { marked, Tokens, type Token } from "marked";
2
+ import { DocC, DocCode, DocList, DocSee } from "./comment.jsx";
3
+
4
+ export interface DocFromMarkdownProps {
5
+ markdown: string;
6
+ }
7
+
8
+ /** Convert markdown to a Csharp doc comment */
9
+ export function DocFromMarkdown(props: DocFromMarkdownProps) {
10
+ const tokens = marked.lexer(props.markdown);
11
+ return renderTokens(tokens);
12
+ }
13
+
14
+ function renderTokens(tokens: Token[]) {
15
+ return (
16
+ <>
17
+ {tokens.map((token, index) => (
18
+ <>
19
+ <DocFromMarkedToken token={token} />
20
+ {token.type === "paragraph" && index !== tokens.length - 1 && <br />}
21
+ </>
22
+ ))}
23
+ </>
24
+ );
25
+ }
26
+
27
+ function DocFromMarkedToken(props: { token: Token }) {
28
+ const { token } = props;
29
+ switch (token.type) {
30
+ case "paragraph":
31
+ return token.tokens ? renderTokens(token.tokens) : null;
32
+ case "code":
33
+ return <DocCode>{token.text}</DocCode>;
34
+ case "codespan":
35
+ return <DocC>{token.text}</DocC>;
36
+ case "list":
37
+ return (
38
+ <DocList
39
+ type={token.ordered ? "number" : "bullet"}
40
+ items={token.items.map((x: Tokens.ListItem) => (
41
+ <>{renderTokens(x.tokens)}</>
42
+ ))}
43
+ />
44
+ );
45
+ case "link":
46
+ return (
47
+ <DocSee href={token.href}>
48
+ {token.tokens && renderTokens(token.tokens)}
49
+ </DocSee>
50
+ );
51
+ case "strong":
52
+ case "em":
53
+ return token.text;
54
+ case "text":
55
+ default:
56
+ return token.raw;
57
+ }
58
+ }
@@ -1,13 +1,21 @@
1
+ export * from "./attributes/attributes.jsx";
1
2
  export * from "./ClassDeclaration.jsx";
2
3
  export * from "./ClassMethod.jsx";
3
4
  export * from "./Declaration.js";
5
+ export * from "./doc/comment.jsx";
6
+ export * from "./doc/from-markdown.jsx";
4
7
  export * from "./EnumDeclaration.jsx";
5
8
  export * from "./interface/declaration.js";
6
9
  export * from "./interface/method.js";
10
+ export * from "./interface/property.js";
7
11
  export * from "./Name.js";
8
12
  export * from "./Namespace.js";
9
- export * from "./Parameters.js";
13
+ export * from "./parameters/parameters.jsx";
10
14
  export * from "./ProjectDirectory.js";
15
+ export * from "./property/property.jsx";
16
+ export * from "./record/declaration.js";
11
17
  export * from "./Reference.js";
12
18
  export * from "./SourceFile.js";
19
+ export type { TypeParameterProps } from "./type-parameters/type-parameter.jsx";
13
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>
@@ -1,6 +1,10 @@
1
+ import { refkey } from "@alloy-js/core";
1
2
  import { Children } from "@alloy-js/core/jsx-runtime";
2
3
  import { describe, expect, it } from "vitest";
3
4
  import { TestNamespace } from "../../../test/utils.jsx";
5
+ import { Attribute } from "../attributes/attributes.jsx";
6
+ import { SourceFile } from "../SourceFile.jsx";
7
+ import { TypeParameterProps } from "../type-parameters/type-parameter.jsx";
4
8
  import { InterfaceDeclaration } from "./declaration.jsx";
5
9
  import { InterfaceMethod } from "./method.jsx";
6
10
 
@@ -103,6 +107,58 @@ it("defines params and return type", () => {
103
107
  `);
104
108
  });
105
109
 
110
+ it("defines optional param", () => {
111
+ const res = (
112
+ <Wrapper>
113
+ <InterfaceMethod
114
+ public
115
+ name="MethodOne"
116
+ parameters={[
117
+ {
118
+ name: "intParam",
119
+ type: "int",
120
+ optional: true,
121
+ },
122
+ ]}
123
+ returns="string"
124
+ />
125
+ </Wrapper>
126
+ );
127
+
128
+ expect(res).toRenderTo(`
129
+ public interface TestInterface
130
+ {
131
+ public string MethodOne(int? intParam);
132
+ }
133
+ `);
134
+ });
135
+
136
+ it("defines optional param with default", () => {
137
+ const res = (
138
+ <Wrapper>
139
+ <InterfaceMethod
140
+ public
141
+ name="MethodOne"
142
+ parameters={[
143
+ {
144
+ name: "intParam",
145
+ type: "int",
146
+ default: 12,
147
+ },
148
+ ]}
149
+ returns="string"
150
+ />
151
+ </Wrapper>
152
+ );
153
+
154
+ expect(res).toRenderTo(`
155
+ public interface TestInterface
156
+ {
157
+ public string MethodOne(int intParam = 12);
158
+ }
159
+ `);
160
+ });
161
+
106
162
  it("specify doc comment", () => {
107
163
  expect(
108
164
  <TestNamespace>
@@ -118,3 +174,120 @@ it("specify doc comment", () => {
118
174
  }
119
175
  `);
120
176
  });
177
+
178
+ it("specify attributes", () => {
179
+ expect(
180
+ <Wrapper>
181
+ <InterfaceMethod name="Test" attributes={[<Attribute name="Test" />]} />
182
+ </Wrapper>,
183
+ ).toRenderTo(`
184
+ public interface TestInterface
185
+ {
186
+ [Test]
187
+ void Test();
188
+ }
189
+ `);
190
+ });
191
+
192
+ describe("with type parameters", () => {
193
+ it("reference parameters", () => {
194
+ const typeParameters: TypeParameterProps[] = [
195
+ {
196
+ name: "T",
197
+ refkey: refkey(),
198
+ },
199
+ {
200
+ name: "U",
201
+ refkey: refkey(),
202
+ },
203
+ ];
204
+
205
+ expect(
206
+ <TestNamespace>
207
+ <SourceFile path="TestFile.cs">
208
+ <InterfaceDeclaration public name="TestInterface">
209
+ <InterfaceMethod
210
+ name="Test"
211
+ public
212
+ typeParameters={typeParameters}
213
+ parameters={[
214
+ {
215
+ name: "paramA",
216
+ type: typeParameters[0].refkey,
217
+ },
218
+ ]}
219
+ returns={typeParameters[0].refkey}
220
+ />
221
+ </InterfaceDeclaration>
222
+ </SourceFile>
223
+ </TestNamespace>,
224
+ ).toRenderTo(`
225
+ namespace TestCode
226
+ {
227
+ public interface TestInterface
228
+ {
229
+ public T Test<T, U>(T paramA);
230
+ }
231
+ }
232
+ `);
233
+ });
234
+
235
+ it("defines with constraints", () => {
236
+ const typeParameters: TypeParameterProps[] = [
237
+ {
238
+ name: "T",
239
+ constraints: "IFoo",
240
+ },
241
+ {
242
+ name: "U",
243
+ constraints: "IBar",
244
+ },
245
+ ];
246
+
247
+ expect(
248
+ <Wrapper>
249
+ <InterfaceMethod public name="Test" typeParameters={typeParameters}>
250
+ // Body
251
+ </InterfaceMethod>
252
+ </Wrapper>,
253
+ ).toRenderTo(`
254
+ public interface TestInterface
255
+ {
256
+ public void Test<T, U>()
257
+ where T : IFoo
258
+ where U : IBar
259
+ {
260
+ // Body
261
+ }
262
+ }
263
+ `);
264
+ });
265
+ });
266
+
267
+ describe("formatting", () => {
268
+ it("Split parameters before type parameters", () => {
269
+ expect(
270
+ <Wrapper>
271
+ <InterfaceMethod
272
+ public
273
+ name="Handle"
274
+ parameters={[
275
+ {
276
+ name: "message",
277
+ type: "Some.Quite.Long.Type.That.Will.Split",
278
+ },
279
+ ]}
280
+ typeParameters={["T"]}
281
+ returns="Some.Quite.Long.Type.That.Will.Split"
282
+ />
283
+ </Wrapper>,
284
+ ).toRenderTo(`
285
+ public interface TestInterface
286
+ {
287
+ public Some.Quite.Long.Type.That.Will.Split Handle<T>(
288
+ Some.Quite.Long.Type.That.Will.Split message
289
+ );
290
+ }
291
+ `);
292
+ });
293
+ });