@alloy-js/csharp 0.23.0-dev.7 → 0.23.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 (102) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/dev/src/components/constructor/constructor.js +69 -9
  3. package/dist/dev/src/components/constructor/constructor.js.map +1 -1
  4. package/dist/dev/src/components/constructor/constructor.test.js +117 -0
  5. package/dist/dev/src/components/constructor/constructor.test.js.map +1 -1
  6. package/dist/dev/src/components/method/method.test.js +64 -0
  7. package/dist/dev/src/components/method/method.test.js.map +1 -1
  8. package/dist/dev/src/components/namespace/namespace.js +2 -1
  9. package/dist/dev/src/components/namespace/namespace.js.map +1 -1
  10. package/dist/dev/src/components/namespace/namespace.test.js +13 -10
  11. package/dist/dev/src/components/namespace/namespace.test.js.map +1 -1
  12. package/dist/dev/src/components/namespace.ref.test.js +54 -42
  13. package/dist/dev/src/components/namespace.ref.test.js.map +1 -1
  14. package/dist/dev/src/components/property/property.js +101 -24
  15. package/dist/dev/src/components/property/property.js.map +1 -1
  16. package/dist/dev/src/components/property/property.test.js +140 -0
  17. package/dist/dev/src/components/property/property.test.js.map +1 -1
  18. package/dist/dev/src/components/source-file/source-file.js +12 -11
  19. package/dist/dev/src/components/source-file/source-file.js.map +1 -1
  20. package/dist/dev/src/identifier-utils.js +45 -0
  21. package/dist/dev/src/identifier-utils.js.map +1 -0
  22. package/dist/dev/src/index.js +2 -0
  23. package/dist/dev/src/index.js.map +1 -1
  24. package/dist/dev/src/keywords.js +39 -0
  25. package/dist/dev/src/keywords.js.map +1 -0
  26. package/dist/dev/src/name-policy.js +29 -6
  27. package/dist/dev/src/name-policy.js.map +1 -1
  28. package/dist/dev/src/name-policy.test.js +167 -0
  29. package/dist/dev/src/name-policy.test.js.map +1 -0
  30. package/dist/src/components/constructor/constructor.d.ts +32 -0
  31. package/dist/src/components/constructor/constructor.d.ts.map +1 -1
  32. package/dist/src/components/constructor/constructor.js +35 -3
  33. package/dist/src/components/constructor/constructor.js.map +1 -1
  34. package/dist/src/components/constructor/constructor.test.js +81 -0
  35. package/dist/src/components/constructor/constructor.test.js.map +1 -1
  36. package/dist/src/components/method/method.test.js +48 -0
  37. package/dist/src/components/method/method.test.js.map +1 -1
  38. package/dist/src/components/namespace/namespace.js +2 -1
  39. package/dist/src/components/namespace/namespace.js.map +1 -1
  40. package/dist/src/components/namespace/namespace.test.js +6 -3
  41. package/dist/src/components/namespace/namespace.test.js.map +1 -1
  42. package/dist/src/components/namespace.ref.test.js +24 -12
  43. package/dist/src/components/namespace.ref.test.js.map +1 -1
  44. package/dist/src/components/property/property.d.ts +42 -4
  45. package/dist/src/components/property/property.d.ts.map +1 -1
  46. package/dist/src/components/property/property.js +64 -11
  47. package/dist/src/components/property/property.js.map +1 -1
  48. package/dist/src/components/property/property.test.js +104 -0
  49. package/dist/src/components/property/property.test.js.map +1 -1
  50. package/dist/src/components/source-file/source-file.d.ts.map +1 -1
  51. package/dist/src/components/source-file/source-file.js +3 -2
  52. package/dist/src/components/source-file/source-file.js.map +1 -1
  53. package/dist/src/identifier-utils.d.ts +22 -0
  54. package/dist/src/identifier-utils.d.ts.map +1 -0
  55. package/dist/src/identifier-utils.js +45 -0
  56. package/dist/src/identifier-utils.js.map +1 -0
  57. package/dist/src/index.d.ts +2 -0
  58. package/dist/src/index.d.ts.map +1 -1
  59. package/dist/src/index.js +2 -0
  60. package/dist/src/index.js.map +1 -1
  61. package/dist/src/keywords.d.ts +32 -0
  62. package/dist/src/keywords.d.ts.map +1 -0
  63. package/dist/src/keywords.js +39 -0
  64. package/dist/src/keywords.js.map +1 -0
  65. package/dist/src/name-policy.d.ts +7 -0
  66. package/dist/src/name-policy.d.ts.map +1 -1
  67. package/dist/src/name-policy.js +29 -6
  68. package/dist/src/name-policy.js.map +1 -1
  69. package/dist/src/name-policy.test.d.ts +2 -0
  70. package/dist/src/name-policy.test.d.ts.map +1 -0
  71. package/dist/src/name-policy.test.js +167 -0
  72. package/dist/src/name-policy.test.js.map +1 -0
  73. package/dist/tsconfig.tsbuildinfo +1 -1
  74. package/docs/api/components/Constructor.md +17 -11
  75. package/docs/api/components/Property.md +30 -30
  76. package/docs/api/contexts/csharp-context.md +21 -0
  77. package/docs/api/contexts/index.md +3 -0
  78. package/docs/api/functions/createCSharpNamePolicy.md +4 -0
  79. package/docs/api/functions/index.md +5 -1
  80. package/docs/api/functions/isCSharpContextualKeyword.md +20 -0
  81. package/docs/api/functions/isCSharpKeyword.md +22 -0
  82. package/docs/api/functions/isValidCSharpIdentifier.md +20 -0
  83. package/docs/api/functions/sanitizeCSharpIdentifier.md +24 -0
  84. package/docs/api/index.md +3 -2
  85. package/docs/api/variables/csharpKeywords.md +11 -0
  86. package/docs/api/variables/index.md +1 -0
  87. package/package.json +8 -8
  88. package/src/components/constructor/constructor.test.tsx +64 -0
  89. package/src/components/constructor/constructor.tsx +81 -1
  90. package/src/components/method/method.test.tsx +36 -0
  91. package/src/components/namespace/namespace.test.tsx +6 -3
  92. package/src/components/namespace/namespace.tsx +2 -2
  93. package/src/components/namespace.ref.test.tsx +24 -12
  94. package/src/components/property/property.test.tsx +89 -0
  95. package/src/components/property/property.tsx +111 -16
  96. package/src/components/source-file/source-file.tsx +1 -4
  97. package/src/identifier-utils.ts +45 -0
  98. package/src/index.ts +2 -0
  99. package/src/keywords.ts +162 -0
  100. package/src/name-policy.test.ts +210 -0
  101. package/src/name-policy.ts +30 -6
  102. package/temp/api.json +317 -7
@@ -9,6 +9,7 @@ Properties for [Constructor](../constructor/) component.
9
9
 
10
10
 
11
11
  <Constructor
12
+ baseConstructor={Children[]}
12
13
  doc={Children}
13
14
  file
14
15
  internal
@@ -17,6 +18,7 @@ Properties for [Constructor](../constructor/) component.
17
18
  protected
18
19
  public
19
20
  refkey={Refkey}
21
+ thisConstructor={Children[]}
20
22
  >
21
23
  {children}
22
24
  </Constructor>
@@ -29,6 +31,7 @@ Properties for [Constructor](../constructor/) component.
29
31
 
30
32
 
31
33
  Constructor({
34
+ baseConstructor: Children[],
32
35
  doc: Children,
33
36
  file: boolean,
34
37
  internal: boolean,
@@ -37,19 +40,22 @@ Properties for [Constructor](../constructor/) component.
37
40
  protected: boolean,
38
41
  public: boolean,
39
42
  refkey: Refkey,
43
+ thisConstructor: Children[],
40
44
  }).children(children)
41
45
  ```
42
46
 
43
47
  ## Props
44
48
 
45
- | | | |
46
- | ---------- | -------------------------------------------------- | ---------------------- |
47
- | children | optional [Children](../../../core/types/children/) | Constructor body |
48
- | doc | optional [Children](../../../core/types/children/) | Doc comment |
49
- | file | optional boolean | |
50
- | internal | optional boolean | |
51
- | parameters | optional [ParameterProps](../parameter/)\[] | Constructor parameters |
52
- | private | optional boolean | |
53
- | protected | optional boolean | |
54
- | public | optional boolean | |
55
- | refkey | optional [Refkey](../../../core/types/refkey/) | Refkey |
49
+ | | | |
50
+ | --------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
51
+ | baseConstructor | optional [Children](../../../core/types/children/)\[] | Arguments to pass to the base class constructor. Renders `: base(args)` between parameter list and body. |
52
+ | children | optional [Children](../../../core/types/children/) | Constructor body |
53
+ | doc | optional [Children](../../../core/types/children/) | Doc comment |
54
+ | file | optional boolean | |
55
+ | internal | optional boolean | |
56
+ | parameters | optional [ParameterProps](../parameter/)\[] | Constructor parameters |
57
+ | private | optional boolean | |
58
+ | protected | optional boolean | |
59
+ | public | optional boolean | |
60
+ | refkey | optional [Refkey](../../../core/types/refkey/) | Refkey |
61
+ | thisConstructor | optional [Children](../../../core/types/children/)\[] | Arguments to pass to another constructor in the same class. Renders `: this(args)` between parameter list and body. |
@@ -16,7 +16,7 @@ Properties for [Property](../property/) component
16
16
  doc={Children}
17
17
  extern
18
18
  file
19
- get
19
+ get={boolean | Children}
20
20
  init
21
21
  initializer={Children}
22
22
  internal
@@ -31,7 +31,7 @@ Properties for [Property](../property/) component
31
31
  refkey={Refkey}
32
32
  required
33
33
  sealed
34
- set
34
+ set={boolean | Children}
35
35
  static
36
36
  type={Children}
37
37
  virtual
@@ -50,7 +50,7 @@ Properties for [Property](../property/) component
50
50
  doc: Children,
51
51
  extern: boolean,
52
52
  file: boolean,
53
- get: boolean,
53
+ get: boolean | Children,
54
54
  init: boolean,
55
55
  initializer: Children,
56
56
  internal: boolean,
@@ -65,7 +65,7 @@ Properties for [Property](../property/) component
65
65
  refkey: Refkey,
66
66
  required: boolean,
67
67
  sealed: boolean,
68
- set: boolean,
68
+ set: boolean | Children,
69
69
  static: boolean,
70
70
  type: Children,
71
71
  virtual: boolean,
@@ -74,32 +74,32 @@ Properties for [Property](../property/) component
74
74
 
75
75
  ## Props
76
76
 
77
- | | | |
78
- | ----------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
79
- | abstract | optional boolean | |
80
- | attributes | optional [AttributesProp](../../types/attributesprop/) | Define attributes to attach |
81
- | doc | optional [Children](../../../core/types/children/) | Doc comment |
82
- | extern | optional boolean | |
83
- | file | optional boolean | |
84
- | get | optional boolean | If property should have a getter |
85
- | init | optional boolean | If property should only be set on the type creation |
86
- | initializer | optional [Children](../../../core/types/children/) | Property initializer |
87
- | internal | optional boolean | |
88
- | name | [Namekey](../../../core/types/namekey/) \| string | |
89
- | new | optional boolean | |
90
- | nullable | optional boolean | Property initializer |
91
- | override | optional boolean | |
92
- | private | optional boolean | |
93
- | protected | optional boolean | |
94
- | public | optional boolean | |
95
- | readonly | optional boolean | |
96
- | refkey | optional [Refkey](../../../core/types/refkey/) | |
97
- | required | optional boolean | Set required modifier on property <https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/required> |
98
- | sealed | optional boolean | |
99
- | set | optional boolean | If property should have a setter |
100
- | static | optional boolean | |
101
- | type | [Children](../../../core/types/children/) | Property type |
102
- | virtual | optional boolean | |
77
+ | | | |
78
+ | ----------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
79
+ | abstract | optional boolean | |
80
+ | attributes | optional [AttributesProp](../../types/attributesprop/) | Define attributes to attach |
81
+ | doc | optional [Children](../../../core/types/children/) | Doc comment |
82
+ | extern | optional boolean | |
83
+ | file | optional boolean | |
84
+ | get | optional boolean \| [Children](../../../core/types/children/) | If property should have a getter. Pass `true` for an auto-property getter (`get;`), or pass children for a getter with a body. |
85
+ | init | optional boolean | If property should only be set on the type creation |
86
+ | initializer | optional [Children](../../../core/types/children/) | Property initializer |
87
+ | internal | optional boolean | |
88
+ | name | [Namekey](../../../core/types/namekey/) \| string | |
89
+ | new | optional boolean | |
90
+ | nullable | optional boolean | Property initializer |
91
+ | override | optional boolean | |
92
+ | private | optional boolean | |
93
+ | protected | optional boolean | |
94
+ | public | optional boolean | |
95
+ | readonly | optional boolean | |
96
+ | refkey | optional [Refkey](../../../core/types/refkey/) | |
97
+ | required | optional boolean | Set required modifier on property <https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/required> |
98
+ | sealed | optional boolean | |
99
+ | set | optional boolean \| [Children](../../../core/types/children/) | If property should have a setter. Pass `true` for an auto-property setter (`set;`), or pass children for a setter with a body. |
100
+ | static | optional boolean | |
101
+ | type | [Children](../../../core/types/children/) | Property type |
102
+ | virtual | optional boolean | |
103
103
 
104
104
  ## Example
105
105
 
@@ -0,0 +1,21 @@
1
+ # csharp context
2
+
3
+ C# contextual keywords that are reserved in certain contexts. While not always reserved, treating them as keywords in generated code avoids subtle context-dependent issues.
4
+
5
+ ```ts
6
+ const csharpContextualKeywords: ReadonlySet<string>
7
+ ```
8
+
9
+ ## Accessor
10
+
11
+ ```ts
12
+ const myContext = useContext(csharpContext);
13
+ ```
14
+
15
+ ## Context interface
16
+
17
+ string
18
+
19
+ ## See also
20
+
21
+ * <https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/#contextual-keywords>
@@ -0,0 +1,3 @@
1
+ # csharp — contexts
2
+
3
+ - [csharp context](csharp-context.md) — C# contextual keywords that are reserved in certain contexts.
@@ -1,5 +1,9 @@
1
1
  # createCSharpNamePolicy
2
2
 
3
+ Creates the C# naming policy with case conversion and keyword escaping.
4
+
5
+ After applying the appropriate case conversion for each element kind, the resulting name is checked against C# reserved and contextual keywords. If it matches (case-sensitively), the name is prefixed with `@`.
6
+
3
7
  ```ts
4
8
  import { createCSharpNamePolicy } from "@alloy-js/csharp";
5
9
 
@@ -4,7 +4,7 @@
4
4
  - [accessibilityFromProps](accessibilityFromProps.md) — import { accessibilityFromProps } from "@alloy-js/csharp";
5
5
  - [computeModifiersPrefix](computeModifiersPrefix.md) — Resolve the modifier prefix
6
6
  - [createClassScope](createClassScope.md) — import { createClassScope } from "@alloy-js/csharp";
7
- - [createCSharpNamePolicy](createCSharpNamePolicy.md) — import { createCSharpNamePolicy } from "@alloy-js/csharp";
7
+ - [createCSharpNamePolicy](createCSharpNamePolicy.md) — Creates the C# naming policy with case conversion and keyword escaping.
8
8
  - [createCSharpNamespaceScope](createCSharpNamespaceScope.md) — import { createCSharpNamespaceScope } from "@alloy-js/csharp";
9
9
  - [createFieldSymbol](createFieldSymbol.md) — import { createFieldSymbol } from "@alloy-js/csharp";
10
10
  - [createLibrary](createLibrary.md) — import { createLibrary } from "@alloy-js/csharp";
@@ -19,9 +19,13 @@
19
19
  - [createVariableSymbol](createVariableSymbol.md) — import { createVariableSymbol } from "@alloy-js/csharp";
20
20
  - [getAccessModifier](getAccessModifier.md) — import { getAccessModifier } from "@alloy-js/csharp";
21
21
  - [getAsyncModifier](getAsyncModifier.md) — import { getAsyncModifier } from "@alloy-js/csharp";
22
+ - [isCSharpContextualKeyword](isCSharpContextualKeyword.md) — Returns true if the given name is a C# contextual keyword.
23
+ - [isCSharpKeyword](isCSharpKeyword.md) — Returns true if the given name is a C# reserved keyword.
24
+ - [isValidCSharpIdentifier](isValidCSharpIdentifier.md) — Checks whether the provided name is a valid C# identifier (without `@` prefix).
22
25
  - [makeModifiers](makeModifiers.md) — import { makeModifiers } from "@alloy-js/csharp";
23
26
  - [nonAccessibilityFromProps](nonAccessibilityFromProps.md) — import { nonAccessibilityFromProps } from "@alloy-js/csharp";
24
27
  - [ref](ref.md) — import { ref } from "@alloy-js/csharp";
28
+ - [sanitizeCSharpIdentifier](sanitizeCSharpIdentifier.md) — Transforms an arbitrary string into a valid C# identifier by replacing invalid characters.
25
29
  - [useCsharpFormatOptions](useCsharpFormatOptions.md) — import { useCsharpFormatOptions } from "@alloy-js/csharp";
26
30
  - [useCSharpNamePolicy](useCSharpNamePolicy.md) — import { useCSharpNamePolicy } from "@alloy-js/csharp";
27
31
  - [useCSharpScope](useCSharpScope.md) — import { useCSharpScope } from "@alloy-js/csharp";
@@ -0,0 +1,20 @@
1
+ # isCSharpContextualKeyword
2
+
3
+ Returns true if the given name is a C# contextual keyword. Contextual keywords are only reserved in specific language contexts and are generally valid as identifiers.
4
+
5
+ ```ts
6
+ import { isCSharpContextualKeyword } from "@alloy-js/csharp";
7
+
8
+
9
+ function isCSharpContextualKeyword(name: string): boolean;
10
+ ```
11
+
12
+ ## Parameters
13
+
14
+ | | | |
15
+ | ---- | ------ | - |
16
+ | name | string | |
17
+
18
+ ## Returns
19
+
20
+ boolean
@@ -0,0 +1,22 @@
1
+ # isCSharpKeyword
2
+
3
+ Returns true if the given name is a C# reserved keyword. The check is case-sensitive, matching C# language semantics.
4
+
5
+ Note: this only checks reserved keywords, not contextual keywords. Contextual keywords are only reserved in specific language contexts and are valid identifiers elsewhere (e.g., `value` is valid as a parameter name). Use [isCSharpContextualKeyword](../iscsharpcontextualkeyword/) to check contextual keywords separately.
6
+
7
+ ```ts
8
+ import { isCSharpKeyword } from "@alloy-js/csharp";
9
+
10
+
11
+ function isCSharpKeyword(name: string): boolean;
12
+ ```
13
+
14
+ ## Parameters
15
+
16
+ | | | |
17
+ | ---- | ------ | - |
18
+ | name | string | |
19
+
20
+ ## Returns
21
+
22
+ boolean
@@ -0,0 +1,20 @@
1
+ # isValidCSharpIdentifier
2
+
3
+ Checks whether the provided name is a valid C# identifier (without `@` prefix). Does not account for keyword conflicts — use [isCSharpKeyword](../iscsharpkeyword/) for that.
4
+
5
+ ```ts
6
+ import { isValidCSharpIdentifier } from "@alloy-js/csharp";
7
+
8
+
9
+ function isValidCSharpIdentifier(name: string): boolean;
10
+ ```
11
+
12
+ ## Parameters
13
+
14
+ | | | |
15
+ | ---- | ------ | - |
16
+ | name | string | |
17
+
18
+ ## Returns
19
+
20
+ boolean true if the name matches C# identifier rules (letter or underscore start, word chars after).
@@ -0,0 +1,24 @@
1
+ # sanitizeCSharpIdentifier
2
+
3
+ Transforms an arbitrary string into a valid C# identifier by replacing invalid characters. The result may still be a C# keyword — callers should combine with keyword escaping if needed.
4
+
5
+ * If the first character is not a letter or underscore, a `_` prefix is added.
6
+ * Subsequent non-word characters are replaced with `_`.
7
+ * Empty strings become `_`.
8
+
9
+ ```ts
10
+ import { sanitizeCSharpIdentifier } from "@alloy-js/csharp";
11
+
12
+
13
+ function sanitizeCSharpIdentifier(name: string): string;
14
+ ```
15
+
16
+ ## Parameters
17
+
18
+ | | | |
19
+ | ---- | ------ | - |
20
+ | name | string | |
21
+
22
+ ## Returns
23
+
24
+ string A string that satisfies C# identifier character rules.
package/docs/api/index.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # @alloy-js/csharp API Reference
2
2
 
3
3
  - [components](components/index.md) (53 items)
4
- - [functions](functions/index.md) (31 items)
4
+ - [contexts](contexts/index.md) (1 items)
5
+ - [functions](functions/index.md) (35 items)
5
6
  - [types](types/index.md) (60 items)
6
- - [variables](variables/index.md) (1 items)
7
+ - [variables](variables/index.md) (2 items)
@@ -0,0 +1,11 @@
1
+ # csharpKeywords
2
+
3
+ C# reserved keywords that cannot be used as identifiers without `@` prefix. These are case-sensitive in C#.
4
+
5
+ ```ts
6
+ csharpKeywords: ReadonlySet<string>
7
+ ```
8
+
9
+ ## See also
10
+
11
+ * <https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/>
@@ -1,3 +1,4 @@
1
1
  # csharp — variables
2
2
 
3
3
  - [Attribute](Attribute.md) — Render a csharp attribute.
4
+ - [csharpKeywords](csharpKeywords.md) — C# reserved keywords that cannot be used as identifiers without `@` prefix.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@alloy-js/csharp",
3
- "version": "0.23.0-dev.7",
3
+ "version": "0.23.0",
4
4
  "description": "Alloy components for CSharp language.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -43,23 +43,23 @@
43
43
  "author": "jhendrix@microsoft.com",
44
44
  "license": "MIT",
45
45
  "dependencies": {
46
- "@alloy-js/core": "~0.22.0 || >= 0.23.0-dev.16",
47
- "@alloy-js/msbuild": "~0.22.0 || >= 0.23.0-dev.2",
48
46
  "change-case": "^5.4.4",
49
47
  "marked": "^16.1.1",
50
- "pathe": "^2.0.3"
48
+ "pathe": "^2.0.3",
49
+ "@alloy-js/core": "~0.23.0",
50
+ "@alloy-js/msbuild": "~0.23.0"
51
51
  },
52
52
  "devDependencies": {
53
- "@alloy-js/cli": "~0.22.0 || >= 0.23.0-dev.6",
54
- "@alloy-js/rollup-plugin": "~0.1.0 || >= 0.1.1-dev.2",
55
- "@alloy-js/typescript": "~0.22.0 || >= 0.23.0-dev.9",
56
53
  "@microsoft/api-extractor": "~7.52.8",
57
54
  "@rollup/plugin-typescript": "^12.1.2",
58
55
  "@types/js-yaml": "^4.0.9",
59
56
  "concurrently": "^9.2.0",
60
57
  "js-yaml": "^4.1.0",
61
58
  "typescript": "^5.8.3",
62
- "vitest": "3.2.4"
59
+ "vitest": "3.2.4",
60
+ "@alloy-js/rollup-plugin": "~0.1.1",
61
+ "@alloy-js/cli": "~0.23.0",
62
+ "@alloy-js/typescript": "~0.23.0"
63
63
  },
64
64
  "type": "module",
65
65
  "scripts": {
@@ -60,3 +60,67 @@ it("renders doc comment", () => {
60
60
  }
61
61
  `);
62
62
  });
63
+
64
+ it("renders : base() initializer", () => {
65
+ expect(
66
+ <TestNamespace>
67
+ <ClassDeclaration public name="DerivedClass" baseType="BaseClass">
68
+ <Constructor
69
+ public
70
+ parameters={[{ name: "name", type: "string" }]}
71
+ baseConstructor={["name"]}
72
+ >
73
+ // body
74
+ </Constructor>
75
+ </ClassDeclaration>
76
+ </TestNamespace>,
77
+ ).toRenderTo(`
78
+ public class DerivedClass : BaseClass
79
+ {
80
+ public DerivedClass(string name) : base(name)
81
+ {
82
+ // body
83
+ }
84
+ }
85
+ `);
86
+ });
87
+
88
+ it("renders : this() initializer", () => {
89
+ expect(
90
+ <TestNamespace>
91
+ <ClassDeclaration public name="MyClass">
92
+ <Constructor public thisConstructor={["0", "0"]}>
93
+ // body
94
+ </Constructor>
95
+ </ClassDeclaration>
96
+ </TestNamespace>,
97
+ ).toRenderTo(`
98
+ public class MyClass
99
+ {
100
+ public MyClass() : this(0, 0)
101
+ {
102
+ // body
103
+ }
104
+ }
105
+ `);
106
+ });
107
+
108
+ it("renders : base() with no arguments", () => {
109
+ expect(
110
+ <TestNamespace>
111
+ <ClassDeclaration public name="DerivedClass" baseType="BaseClass">
112
+ <Constructor public baseConstructor={[]}>
113
+ // body
114
+ </Constructor>
115
+ </ClassDeclaration>
116
+ </TestNamespace>,
117
+ ).toRenderTo(`
118
+ public class DerivedClass : BaseClass
119
+ {
120
+ public DerivedClass() : base()
121
+ {
122
+ // body
123
+ }
124
+ }
125
+ `);
126
+ });
@@ -1,5 +1,12 @@
1
1
  import { MethodScope } from "#components/method-scope.jsx";
2
- import { Block, MemberDeclaration, MemberName, Refkey } from "@alloy-js/core";
2
+ import {
3
+ Block,
4
+ For,
5
+ Indent,
6
+ MemberDeclaration,
7
+ MemberName,
8
+ Refkey,
9
+ } from "@alloy-js/core";
3
10
  import { Children } from "@alloy-js/core/jsx-runtime";
4
11
  import {
5
12
  AccessModifiers,
@@ -24,11 +31,51 @@ export interface ConstructorProps extends AccessModifiers {
24
31
  /** Refkey */
25
32
  refkey?: Refkey;
26
33
 
34
+ /**
35
+ * Arguments to pass to the base class constructor.
36
+ * Renders `: base(args)` between parameter list and body.
37
+ *
38
+ * @example
39
+ * ```tsx
40
+ * <Constructor public baseConstructor={["name", "42"]}>
41
+ * ```
42
+ * This will produce:
43
+ * ```csharp
44
+ * public MyClass(...) : base(name, 42)
45
+ * {
46
+ * }
47
+ * ```
48
+ */
49
+ baseConstructor?: Children[];
50
+
51
+ /**
52
+ * Arguments to pass to another constructor in the same class.
53
+ * Renders `: this(args)` between parameter list and body.
54
+ *
55
+ * @example
56
+ * ```tsx
57
+ * <Constructor public thisConstructor={["0", "0"]}>
58
+ * ```
59
+ * This will produce:
60
+ * ```csharp
61
+ * public MyClass() : this(0, 0)
62
+ * {
63
+ * }
64
+ * ```
65
+ */
66
+ thisConstructor?: Children[];
67
+
27
68
  /** Constructor body */
28
69
  children?: Children;
29
70
  }
30
71
 
31
72
  export function Constructor(props: ConstructorProps) {
73
+ if (props.baseConstructor && props.thisConstructor) {
74
+ throw new Error(
75
+ "Cannot use both 'baseConstructor' and 'thisConstructor' on the same constructor",
76
+ );
77
+ }
78
+
32
79
  const scope = useNamedTypeScope();
33
80
 
34
81
  const name = scope.ownerSymbol.name;
@@ -39,6 +86,13 @@ export function Constructor(props: ConstructorProps) {
39
86
 
40
87
  const modifiers = computeModifiersPrefix([getAccessModifier(props)]);
41
88
 
89
+ const initializer =
90
+ props.baseConstructor ?
91
+ <ConstructorInitializer keyword="base" args={props.baseConstructor} />
92
+ : props.thisConstructor ?
93
+ <ConstructorInitializer keyword="this" args={props.thisConstructor} />
94
+ : null;
95
+
42
96
  return (
43
97
  <MemberDeclaration symbol={ctorSymbol}>
44
98
  <MethodScope>
@@ -46,8 +100,34 @@ export function Constructor(props: ConstructorProps) {
46
100
  {modifiers}
47
101
  <MemberName />
48
102
  <Parameters parameters={props.parameters} />
103
+ {initializer}
49
104
  <Block newline>{props.children}</Block>
50
105
  </MethodScope>
51
106
  </MemberDeclaration>
52
107
  );
53
108
  }
109
+
110
+ interface ConstructorInitializerProps {
111
+ keyword: "base" | "this";
112
+ args: Children[];
113
+ }
114
+
115
+ function ConstructorInitializer(props: ConstructorInitializerProps) {
116
+ return (
117
+ <group>
118
+ {" : "}
119
+ {props.keyword}(
120
+ <Indent nobreak>
121
+ <For each={props.args} joiner={", "}>
122
+ {(arg) => (
123
+ <>
124
+ <softline />
125
+ {arg}
126
+ </>
127
+ )}
128
+ </For>
129
+ </Indent>
130
+ <softline />)
131
+ </group>
132
+ );
133
+ }
@@ -207,3 +207,39 @@ describe("format", () => {
207
207
  `);
208
208
  });
209
209
  });
210
+
211
+ describe("name policy deduplication", () => {
212
+ it("deduplicates parameters that collide after case conversion", () => {
213
+ const params = [
214
+ { name: "my-param", type: "int" },
215
+ { name: "myParam", type: "string" },
216
+ ];
217
+ expect(
218
+ <Wrapper>
219
+ <Method public name="MethodOne" parameters={params} />
220
+ </Wrapper>,
221
+ ).toRenderTo(`
222
+ public class TestClass
223
+ {
224
+ public void MethodOne(int myParam, string myParam_2) {}
225
+ }
226
+ `);
227
+ });
228
+
229
+ it("deduplicates parameters that are keywords", () => {
230
+ const params = [
231
+ { name: "string", type: "int" },
232
+ { name: "string", type: "bool" },
233
+ ];
234
+ expect(
235
+ <Wrapper>
236
+ <Method public name="MethodOne" parameters={params} />
237
+ </Wrapper>,
238
+ ).toRenderTo(`
239
+ public class TestClass
240
+ {
241
+ public void MethodOne(int @string, bool string_2) {}
242
+ }
243
+ `);
244
+ });
245
+ });
@@ -138,8 +138,10 @@ it("define nested namespace in sourcefile", () => {
138
138
  );
139
139
 
140
140
  expect(tree).toRenderTo(`
141
- namespace Base {
142
- namespace Namespace1.Namespace2 {
141
+ namespace Base
142
+ {
143
+ namespace Namespace1.Namespace2
144
+ {
143
145
  public class Model1;
144
146
  }
145
147
  }
@@ -170,7 +172,8 @@ it("contains a struct with a private field initialized by a constructor", () =>
170
172
  );
171
173
 
172
174
  expect(tree).toRenderTo(d`
173
- namespace TestNamespace.Test {
175
+ namespace TestNamespace.Test
176
+ {
174
177
  public struct MyStruct
175
178
  {
176
179
  private int _value;
@@ -38,8 +38,8 @@ export function Namespace(props: NamespaceProps) {
38
38
  <NamespaceName
39
39
  symbol={namespaceSymbol}
40
40
  relative={!!hasOuterNamespace}
41
- />{" "}
42
- <Block>
41
+ />
42
+ <Block newline>
43
43
  <NamespaceScopes symbol={namespaceSymbol} stopAt={nsContext?.symbol}>
44
44
  {props.children}
45
45
  </NamespaceScopes>