@alloy-js/csharp 0.1.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.
- package/LICENSE.txt +7 -0
- package/api-extractor.json +4 -0
- package/babel.config.cjs +4 -0
- package/dist/src/components/Class.d.ts +33 -0
- package/dist/src/components/Class.d.ts.map +1 -0
- package/dist/src/components/Class.js +170 -0
- package/dist/src/components/Class.js.map +1 -0
- package/dist/src/components/Declaration.d.ts +8 -0
- package/dist/src/components/Declaration.d.ts.map +1 -0
- package/dist/src/components/Declaration.js +18 -0
- package/dist/src/components/Declaration.js.map +1 -0
- package/dist/src/components/Enum.d.ts +13 -0
- package/dist/src/components/Enum.d.ts.map +1 -0
- package/dist/src/components/Enum.js +65 -0
- package/dist/src/components/Enum.js.map +1 -0
- package/dist/src/components/Name.d.ts +2 -0
- package/dist/src/components/Name.d.ts.map +1 -0
- package/dist/src/components/Name.js +12 -0
- package/dist/src/components/Name.js.map +1 -0
- package/dist/src/components/Namespace.d.ts +11 -0
- package/dist/src/components/Namespace.d.ts.map +1 -0
- package/dist/src/components/Namespace.js +35 -0
- package/dist/src/components/Namespace.js.map +1 -0
- package/dist/src/components/Parameters.d.ts +13 -0
- package/dist/src/components/Parameters.d.ts.map +1 -0
- package/dist/src/components/Parameters.js +34 -0
- package/dist/src/components/Parameters.js.map +1 -0
- package/dist/src/components/ProjectDirectory.d.ts +12 -0
- package/dist/src/components/ProjectDirectory.d.ts.map +1 -0
- package/dist/src/components/ProjectDirectory.js +48 -0
- package/dist/src/components/ProjectDirectory.js.map +1 -0
- package/dist/src/components/Reference.d.ts +6 -0
- package/dist/src/components/Reference.d.ts.map +1 -0
- package/dist/src/components/Reference.js +9 -0
- package/dist/src/components/Reference.js.map +1 -0
- package/dist/src/components/SourceFile.d.ts +12 -0
- package/dist/src/components/SourceFile.d.ts.map +1 -0
- package/dist/src/components/SourceFile.js +72 -0
- package/dist/src/components/SourceFile.js.map +1 -0
- package/dist/src/components/UsingDirective.d.ts +5 -0
- package/dist/src/components/UsingDirective.d.ts.map +1 -0
- package/dist/src/components/UsingDirective.js +13 -0
- package/dist/src/components/UsingDirective.js.map +1 -0
- package/dist/src/components/index.d.ts +11 -0
- package/dist/src/components/index.d.ts.map +1 -0
- package/dist/src/components/index.js +11 -0
- package/dist/src/components/index.js.map +1 -0
- package/dist/src/components/stc/index.d.ts +43 -0
- package/dist/src/components/stc/index.d.ts.map +1 -0
- package/dist/src/components/stc/index.js +13 -0
- package/dist/src/components/stc/index.js.map +1 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +5 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/modifiers.d.ts +5 -0
- package/dist/src/modifiers.d.ts.map +1 -0
- package/dist/src/modifiers.js +35 -0
- package/dist/src/modifiers.js.map +1 -0
- package/dist/src/name-policy.d.ts +5 -0
- package/dist/src/name-policy.d.ts.map +1 -0
- package/dist/src/name-policy.js +30 -0
- package/dist/src/name-policy.js.map +1 -0
- package/dist/src/symbols/csharp-output-symbol.d.ts +7 -0
- package/dist/src/symbols/csharp-output-symbol.d.ts.map +1 -0
- package/dist/src/symbols/csharp-output-symbol.js +20 -0
- package/dist/src/symbols/csharp-output-symbol.js.map +1 -0
- package/dist/src/symbols/index.d.ts +4 -0
- package/dist/src/symbols/index.d.ts.map +1 -0
- package/dist/src/symbols/index.js +4 -0
- package/dist/src/symbols/index.js.map +1 -0
- package/dist/src/symbols/reference.d.ts +3 -0
- package/dist/src/symbols/reference.d.ts.map +1 -0
- package/dist/src/symbols/reference.js +55 -0
- package/dist/src/symbols/reference.js.map +1 -0
- package/dist/src/symbols/scopes.d.ts +16 -0
- package/dist/src/symbols/scopes.d.ts.map +1 -0
- package/dist/src/symbols/scopes.js +37 -0
- package/dist/src/symbols/scopes.js.map +1 -0
- package/dist/test/class.test.d.ts +2 -0
- package/dist/test/class.test.d.ts.map +1 -0
- package/dist/test/enum.test.d.ts +2 -0
- package/dist/test/enum.test.d.ts.map +1 -0
- package/dist/test/namespace.test.d.ts +2 -0
- package/dist/test/namespace.test.d.ts.map +1 -0
- package/dist/test/projectdirectory.test.d.ts +2 -0
- package/dist/test/projectdirectory.test.d.ts.map +1 -0
- package/dist/test/sourcefile.test.d.ts +2 -0
- package/dist/test/sourcefile.test.d.ts.map +1 -0
- package/dist/test/using.test.d.ts +2 -0
- package/dist/test/using.test.d.ts.map +1 -0
- package/dist/test/utils.d.ts +6 -0
- package/dist/test/utils.d.ts.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +51 -0
- package/src/components/Class.tsx +210 -0
- package/src/components/Declaration.tsx +17 -0
- package/src/components/Enum.tsx +74 -0
- package/src/components/Name.tsx +11 -0
- package/src/components/Namespace.tsx +39 -0
- package/src/components/Parameters.tsx +52 -0
- package/src/components/ProjectDirectory.tsx +54 -0
- package/src/components/Reference.tsx +13 -0
- package/src/components/SourceFile.tsx +69 -0
- package/src/components/UsingDirective.tsx +19 -0
- package/src/components/index.ts +10 -0
- package/src/components/stc/index.ts +13 -0
- package/src/index.ts +4 -0
- package/src/modifiers.ts +45 -0
- package/src/name-policy.ts +41 -0
- package/src/symbols/csharp-output-symbol.ts +26 -0
- package/src/symbols/index.ts +3 -0
- package/src/symbols/reference.ts +65 -0
- package/src/symbols/scopes.ts +60 -0
- package/temp/api.json +3474 -0
- package/test/class.test.tsx +249 -0
- package/test/enum.test.tsx +147 -0
- package/test/namespace.test.tsx +59 -0
- package/test/projectdirectory.test.tsx +106 -0
- package/test/sourcefile.test.tsx +46 -0
- package/test/using.test.tsx +97 -0
- package/test/utils.tsx +69 -0
- package/tsconfig.json +11 -0
- package/tsdoc-metadata.json +11 -0
- package/vitest.config.ts +18 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import * as core from "@alloy-js/core";
|
|
2
|
+
import {
|
|
3
|
+
AccessModifier,
|
|
4
|
+
getAccessModifier,
|
|
5
|
+
getMethodModifier,
|
|
6
|
+
MethodModifier,
|
|
7
|
+
} from "../modifiers.js";
|
|
8
|
+
import { CSharpElements, useCSharpNamePolicy } from "../name-policy.js";
|
|
9
|
+
import { CSharpOutputSymbol } from "../symbols/csharp-output-symbol.js";
|
|
10
|
+
import { createCSharpMemberScope, useCSharpScope } from "../symbols/scopes.js";
|
|
11
|
+
import { Name } from "./Name.js";
|
|
12
|
+
import { ParameterProps, Parameters } from "./Parameters.js";
|
|
13
|
+
|
|
14
|
+
// properties for creating a class
|
|
15
|
+
export interface ClassProps extends Omit<core.DeclarationProps, "nameKind"> {
|
|
16
|
+
name: string;
|
|
17
|
+
accessModifier?: AccessModifier;
|
|
18
|
+
typeParameters?: Record<string, core.Refkey>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// a C# class declaration
|
|
22
|
+
export function Class(props: ClassProps) {
|
|
23
|
+
const name = useCSharpNamePolicy().getName(props.name!, "class");
|
|
24
|
+
const scope = useCSharpScope();
|
|
25
|
+
|
|
26
|
+
const thisClassSymbol = scope.binder.createSymbol<CSharpOutputSymbol>({
|
|
27
|
+
name: name,
|
|
28
|
+
scope,
|
|
29
|
+
refkey: props.refkey ?? core.refkey(props.name),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// this creates a new scope for the class definition.
|
|
33
|
+
// members will automatically "inherit" this scope so
|
|
34
|
+
// that refkeys to them will produce the fully-qualified
|
|
35
|
+
// name e.g. Foo.Bar.
|
|
36
|
+
const thisClassScope = createCSharpMemberScope(
|
|
37
|
+
scope.binder,
|
|
38
|
+
scope,
|
|
39
|
+
thisClassSymbol,
|
|
40
|
+
"class-decl",
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
let typeParams: string | undefined;
|
|
44
|
+
if (props.typeParameters) {
|
|
45
|
+
const typeParamNames = new Array<string>();
|
|
46
|
+
for (const entry of Object.entries(props.typeParameters)) {
|
|
47
|
+
typeParamNames.push(
|
|
48
|
+
useCSharpNamePolicy().getName(entry[0], "type-parameter"),
|
|
49
|
+
);
|
|
50
|
+
// create a symbol for each type param so its
|
|
51
|
+
// refkey resolves to the type param's name
|
|
52
|
+
scope.binder.createSymbol<CSharpOutputSymbol>({
|
|
53
|
+
name: entry[0],
|
|
54
|
+
scope: thisClassScope,
|
|
55
|
+
refkey: entry[1],
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
typeParams = `<${typeParamNames.join(", ")}>`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return <core.Declaration symbol={thisClassSymbol}>
|
|
62
|
+
{getAccessModifier(props.accessModifier)}class <Name />{typeParams}{!props.children && ";"}{props.children &&
|
|
63
|
+
<>
|
|
64
|
+
{"\n{"}
|
|
65
|
+
<core.Scope value={thisClassScope}>
|
|
66
|
+
{props.children}
|
|
67
|
+
</core.Scope>
|
|
68
|
+
{"}"}
|
|
69
|
+
</>
|
|
70
|
+
}
|
|
71
|
+
</core.Declaration>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface ClassConstructorProps {
|
|
75
|
+
accessModifier?: AccessModifier;
|
|
76
|
+
parameters?: Array<ParameterProps>;
|
|
77
|
+
refkey?: core.Refkey;
|
|
78
|
+
symbol?: core.OutputSymbol;
|
|
79
|
+
children?: core.Children;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// a C# class constructor
|
|
83
|
+
export function ClassConstructor(props: ClassConstructorProps) {
|
|
84
|
+
const scope = useCSharpScope();
|
|
85
|
+
if (scope.kind !== "member" || scope.name !== "class-decl") {
|
|
86
|
+
throw new Error(
|
|
87
|
+
"can't define a class constructor outside of a class-decl scope",
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// fetch the class name from the scope
|
|
92
|
+
const name = useCSharpNamePolicy().getName(scope.owner.name, "class-method");
|
|
93
|
+
const ctorSymbol = scope.binder.createSymbol<CSharpOutputSymbol>({
|
|
94
|
+
name: name,
|
|
95
|
+
scope,
|
|
96
|
+
refkey: props.refkey ?? core.refkey(name),
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// scope for ctor declaration
|
|
100
|
+
const ctorDeclScope = createCSharpMemberScope(
|
|
101
|
+
scope.binder,
|
|
102
|
+
scope,
|
|
103
|
+
ctorSymbol,
|
|
104
|
+
"constructor-decl",
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const accessModifier = getAccessModifier(props.accessModifier);
|
|
108
|
+
const params = props.parameters ?
|
|
109
|
+
<Parameters parameters={props.parameters} />
|
|
110
|
+
: "";
|
|
111
|
+
|
|
112
|
+
// note that scope wraps the ctor decl so that the params get the correct scope
|
|
113
|
+
return <core.Declaration symbol={ctorSymbol}>
|
|
114
|
+
<core.Scope value={ctorDeclScope}>
|
|
115
|
+
{accessModifier}<Name />({params}){!props.children && " {}"}{props.children &&
|
|
116
|
+
<>
|
|
117
|
+
{"\n{"}
|
|
118
|
+
{props.children}
|
|
119
|
+
{"}"}
|
|
120
|
+
</>
|
|
121
|
+
}
|
|
122
|
+
</core.Scope>
|
|
123
|
+
</core.Declaration>;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// properties for creating a class member
|
|
127
|
+
export interface ClassMemberProps {
|
|
128
|
+
name: string;
|
|
129
|
+
type: core.Children;
|
|
130
|
+
accessModifier?: AccessModifier;
|
|
131
|
+
refkey?: core.Refkey;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// a C# class member (i.e. a field within a class like "private int count")
|
|
135
|
+
export function ClassMember(props: ClassMemberProps) {
|
|
136
|
+
let nameElement: CSharpElements = "class-member-private";
|
|
137
|
+
if (props.accessModifier === "public") {
|
|
138
|
+
nameElement = "class-member-public";
|
|
139
|
+
}
|
|
140
|
+
const name = useCSharpNamePolicy().getName(props.name, nameElement);
|
|
141
|
+
const scope = useCSharpScope();
|
|
142
|
+
if (scope.kind !== "member" || scope.name !== "class-decl") {
|
|
143
|
+
throw new Error(
|
|
144
|
+
"can't define a class member outside of a class-decl scope",
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const memberSymbol = scope.binder.createSymbol<CSharpOutputSymbol>({
|
|
149
|
+
name: name,
|
|
150
|
+
scope,
|
|
151
|
+
refkey: props.refkey ?? core.refkey(props.name),
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
return <core.Declaration symbol={memberSymbol}>
|
|
155
|
+
{getAccessModifier(props.accessModifier)}{props.type} <Name />;
|
|
156
|
+
</core.Declaration>;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// properties for creating a method
|
|
160
|
+
export interface ClassMethodProps
|
|
161
|
+
extends Omit<core.DeclarationProps, "nameKind"> {
|
|
162
|
+
name: string;
|
|
163
|
+
accessModifier?: AccessModifier;
|
|
164
|
+
methodModifier?: MethodModifier;
|
|
165
|
+
parameters?: Array<ParameterProps>;
|
|
166
|
+
returns?: core.Children;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// a C# class method
|
|
170
|
+
export function ClassMethod(props: ClassMethodProps) {
|
|
171
|
+
const name = useCSharpNamePolicy().getName(props.name!, "class-method");
|
|
172
|
+
const scope = useCSharpScope();
|
|
173
|
+
if (scope.kind !== "member" || scope.name !== "class-decl") {
|
|
174
|
+
throw new Error("can't define a class method outside of a class scope");
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const methodSymbol = scope.binder.createSymbol<CSharpOutputSymbol>({
|
|
178
|
+
name: name,
|
|
179
|
+
scope,
|
|
180
|
+
refkey: props.refkey ?? core.refkey(props.name),
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
// scope for method declaration
|
|
184
|
+
const methodScope = createCSharpMemberScope(
|
|
185
|
+
scope.binder,
|
|
186
|
+
scope,
|
|
187
|
+
methodSymbol,
|
|
188
|
+
"method-decl",
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
const accessModifier = getAccessModifier(props.accessModifier);
|
|
192
|
+
const methodModifier = getMethodModifier(props.methodModifier);
|
|
193
|
+
const params = props.parameters ?
|
|
194
|
+
<Parameters parameters={props.parameters} />
|
|
195
|
+
: "";
|
|
196
|
+
const returns = props.returns ?? "void";
|
|
197
|
+
|
|
198
|
+
// note that scope wraps the method decl so that the params get the correct scope
|
|
199
|
+
return <core.Declaration symbol={methodSymbol}>
|
|
200
|
+
<core.Scope value={methodScope}>
|
|
201
|
+
{accessModifier}{methodModifier}{returns} <Name />({params}){!props.children && " {}"}{props.children &&
|
|
202
|
+
<>
|
|
203
|
+
{"\n{"}
|
|
204
|
+
{props.children}
|
|
205
|
+
{"}"}
|
|
206
|
+
</>
|
|
207
|
+
}
|
|
208
|
+
</core.Scope>
|
|
209
|
+
</core.Declaration>;
|
|
210
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as core from "@alloy-js/core";
|
|
2
|
+
import { createCSharpSymbol } from "../symbols/csharp-output-symbol.js";
|
|
3
|
+
|
|
4
|
+
// properties for creating a declaration
|
|
5
|
+
export interface DeclarationProps {
|
|
6
|
+
name: string;
|
|
7
|
+
refkey?: core.Refkey;
|
|
8
|
+
children?: core.Children;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// declares a symbol in the program (class, enum, interface etc)
|
|
12
|
+
export function Declaration(props: DeclarationProps) {
|
|
13
|
+
const sym = createCSharpSymbol(props);
|
|
14
|
+
return <core.Declaration symbol={sym}>
|
|
15
|
+
{props.children}
|
|
16
|
+
</core.Declaration>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as core from "@alloy-js/core";
|
|
2
|
+
import { AccessModifier, getAccessModifier } from "../modifiers.js";
|
|
3
|
+
import { useCSharpNamePolicy } from "../name-policy.js";
|
|
4
|
+
import { CSharpOutputSymbol } from "../symbols/csharp-output-symbol.js";
|
|
5
|
+
import { createCSharpMemberScope, useCSharpScope } from "../symbols/scopes.js";
|
|
6
|
+
import { Name } from "./Name.jsx";
|
|
7
|
+
|
|
8
|
+
// properties for creating an enum
|
|
9
|
+
export interface EnumProps extends Omit<core.DeclarationProps, "nameKind"> {
|
|
10
|
+
name: string;
|
|
11
|
+
accessModifier?: AccessModifier;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// a C# enum declaration
|
|
15
|
+
export function Enum(props: EnumProps) {
|
|
16
|
+
const name = useCSharpNamePolicy().getName(props.name!, "enum");
|
|
17
|
+
const scope = useCSharpScope();
|
|
18
|
+
|
|
19
|
+
const thisEnumSymbol = scope.binder.createSymbol<CSharpOutputSymbol>({
|
|
20
|
+
name: name,
|
|
21
|
+
scope,
|
|
22
|
+
refkey: props.refkey ?? core.refkey(props.name),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// this creates a new scope for the enum definition.
|
|
26
|
+
// members will automatically "inherit" this scope so
|
|
27
|
+
// that refkeys to them will produce the fully-qualified
|
|
28
|
+
// name e.g. Foo.Bar.
|
|
29
|
+
const thisEnumScope = createCSharpMemberScope(
|
|
30
|
+
scope.binder,
|
|
31
|
+
scope,
|
|
32
|
+
thisEnumSymbol,
|
|
33
|
+
"enum-decl",
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
return <core.Declaration symbol={thisEnumSymbol}>
|
|
37
|
+
{getAccessModifier(props.accessModifier)}enum <Name />{!props.children && ";"}{props.children &&
|
|
38
|
+
<>
|
|
39
|
+
{"\n{"}
|
|
40
|
+
<core.Scope value={thisEnumScope}>
|
|
41
|
+
{props.children}
|
|
42
|
+
</core.Scope>
|
|
43
|
+
{"}"}
|
|
44
|
+
</>
|
|
45
|
+
}
|
|
46
|
+
</core.Declaration>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// properties for creating a C# enum member
|
|
50
|
+
export interface EnumMemberProps {
|
|
51
|
+
name: string;
|
|
52
|
+
refkey?: core.Refkey;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// a member within a C# enum
|
|
56
|
+
export function EnumMember(props: EnumMemberProps) {
|
|
57
|
+
const scope = useCSharpScope();
|
|
58
|
+
if (scope.kind === "member" && scope.name !== "enum-decl") {
|
|
59
|
+
throw new Error(
|
|
60
|
+
"can't define an enum member outside of an enum-decl scope",
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const name = useCSharpNamePolicy().getName(props.name, "enum-member");
|
|
65
|
+
const thisEnumValueSymbol = scope.binder.createSymbol<CSharpOutputSymbol>({
|
|
66
|
+
name: name,
|
|
67
|
+
scope,
|
|
68
|
+
refkey: props.refkey ?? core.refkey(props.name),
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return <core.Declaration symbol={thisEnumValueSymbol}>
|
|
72
|
+
<Name />
|
|
73
|
+
</core.Declaration>;
|
|
74
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as core from "@alloy-js/core";
|
|
2
|
+
|
|
3
|
+
// the name within the current declaration
|
|
4
|
+
export function Name() {
|
|
5
|
+
const declSymbol = core.useContext(core.DeclarationContext);
|
|
6
|
+
if (!declSymbol) {
|
|
7
|
+
throw new Error("missing declaration context");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return <>{declSymbol.name}</>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import * as core from "@alloy-js/core";
|
|
2
|
+
import { createCSharpNamespaceScope } from "../symbols/scopes.js";
|
|
3
|
+
|
|
4
|
+
// contains the info for the current namespace
|
|
5
|
+
export interface NamespaceContext {
|
|
6
|
+
name: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const NamespaceContext = core.createContext<NamespaceContext>();
|
|
10
|
+
|
|
11
|
+
// returns the current namespace
|
|
12
|
+
export function useNamespace(): NamespaceContext | undefined {
|
|
13
|
+
return core.useContext(NamespaceContext) as NamespaceContext;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// properties for creating a C# namespace
|
|
17
|
+
export interface NamespaceProps {
|
|
18
|
+
name: string;
|
|
19
|
+
children?: core.Children;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// a C# namespace. contains one or more source files
|
|
23
|
+
export function Namespace(props: NamespaceProps) {
|
|
24
|
+
const scope = createCSharpNamespaceScope(
|
|
25
|
+
core.useBinder(),
|
|
26
|
+
core.useScope(),
|
|
27
|
+
props.name,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const namespaceCtx: NamespaceContext = {
|
|
31
|
+
name: props.name,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
return <NamespaceContext.Provider value={namespaceCtx}>
|
|
35
|
+
<core.Scope value={scope}>
|
|
36
|
+
{props.children}
|
|
37
|
+
</core.Scope>
|
|
38
|
+
</NamespaceContext.Provider>;
|
|
39
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as core from "@alloy-js/core";
|
|
2
|
+
import { useCSharpNamePolicy } from "../name-policy.js";
|
|
3
|
+
import { CSharpOutputSymbol } from "../symbols/csharp-output-symbol.js";
|
|
4
|
+
import { useCSharpScope } from "../symbols/scopes.js";
|
|
5
|
+
import { Name } from "./Name.js";
|
|
6
|
+
|
|
7
|
+
export interface ParameterProps {
|
|
8
|
+
name: string;
|
|
9
|
+
type: core.Children;
|
|
10
|
+
refkey?: core.Refkey;
|
|
11
|
+
symbol?: core.OutputSymbol;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// a constructor/method parameter
|
|
15
|
+
export function Parameter(props: ParameterProps) {
|
|
16
|
+
const name = useCSharpNamePolicy().getName(props.name, "parameter");
|
|
17
|
+
const scope = useCSharpScope();
|
|
18
|
+
if (
|
|
19
|
+
scope.kind !== "member" ||
|
|
20
|
+
(scope.name !== "constructor-decl" && scope.name !== "method-decl")
|
|
21
|
+
) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
"can't define a parameter outside of a constructor-decl or method-decl scope",
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const memberSymbol = scope.binder.createSymbol<CSharpOutputSymbol>({
|
|
28
|
+
name: name,
|
|
29
|
+
scope,
|
|
30
|
+
refkey: props.refkey ?? core.refkey(props.name),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return <core.Declaration symbol={memberSymbol}>
|
|
34
|
+
{props.type} <Name />
|
|
35
|
+
</core.Declaration>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ParametersProps {
|
|
39
|
+
// param name and type
|
|
40
|
+
parameters: Array<ParameterProps>;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// a collection of parameters
|
|
44
|
+
export function Parameters(props: ParametersProps): Array<core.Child | string> {
|
|
45
|
+
return core.mapJoin(
|
|
46
|
+
props.parameters,
|
|
47
|
+
(param) => {
|
|
48
|
+
return <Parameter {...param} />;
|
|
49
|
+
},
|
|
50
|
+
{ joiner: ", " },
|
|
51
|
+
);
|
|
52
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as core from "@alloy-js/core";
|
|
2
|
+
import { join } from "pathe";
|
|
3
|
+
|
|
4
|
+
// properties for creating the project directory
|
|
5
|
+
export interface ProjectDirectoryProps {
|
|
6
|
+
// the name of the project directory
|
|
7
|
+
name: string;
|
|
8
|
+
|
|
9
|
+
// the semver of the project
|
|
10
|
+
version: string;
|
|
11
|
+
|
|
12
|
+
// project description
|
|
13
|
+
description: string;
|
|
14
|
+
|
|
15
|
+
// parent path where the project directory will be created
|
|
16
|
+
path: string;
|
|
17
|
+
|
|
18
|
+
// directory name for source files. defaults to "src"
|
|
19
|
+
srcDir?: string;
|
|
20
|
+
|
|
21
|
+
// the .NET TFM for this project. defaults to net8.0
|
|
22
|
+
targetFrameworkMoniker?: string;
|
|
23
|
+
|
|
24
|
+
// child components of the project
|
|
25
|
+
children?: core.Children;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// the top-level C# project directory. includes a csproj file
|
|
29
|
+
export function ProjectDirectory(props: ProjectDirectoryProps) {
|
|
30
|
+
if (!props.srcDir) {
|
|
31
|
+
props.srcDir = "src";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!props.targetFrameworkMoniker) {
|
|
35
|
+
props.targetFrameworkMoniker = "net8.0";
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return <core.SourceDirectory path={join(props.path, props.name)}>
|
|
39
|
+
<core.SourceFile path={props.name+".csproj"} filetype="xml">
|
|
40
|
+
{core.code`
|
|
41
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
|
42
|
+
<PropertyGroup>
|
|
43
|
+
<Version>${props.version}</Version>
|
|
44
|
+
<Description>${props.description}</Description>
|
|
45
|
+
<TargetFramework>${props.targetFrameworkMoniker}</TargetFramework>
|
|
46
|
+
</PropertyGroup>
|
|
47
|
+
</Project>
|
|
48
|
+
`}
|
|
49
|
+
</core.SourceFile>
|
|
50
|
+
<core.SourceDirectory path={props.srcDir}>
|
|
51
|
+
{props.children}
|
|
52
|
+
</core.SourceDirectory>
|
|
53
|
+
</core.SourceDirectory>;
|
|
54
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as core from "@alloy-js/core";
|
|
2
|
+
import { ref } from "../symbols/reference.js";
|
|
3
|
+
|
|
4
|
+
export interface ReferenceProps {
|
|
5
|
+
refkey: core.Refkey;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// used to resolve refkey references within source files
|
|
9
|
+
export function Reference({ refkey }: ReferenceProps) {
|
|
10
|
+
const reference = ref(refkey);
|
|
11
|
+
|
|
12
|
+
return <>{reference}</>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as core from "@alloy-js/core";
|
|
2
|
+
import { useNamespace } from "./Namespace.jsx";
|
|
3
|
+
import { Reference } from "./Reference.jsx";
|
|
4
|
+
import { UsingDirective } from "./UsingDirective.jsx";
|
|
5
|
+
|
|
6
|
+
// contains the info for the current source file
|
|
7
|
+
export interface SourceFileContext {
|
|
8
|
+
// adds a namespace to the array of using statements
|
|
9
|
+
addUsing(namespace: string): void;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const SourceFileContext = core.createContext<SourceFileContext>();
|
|
13
|
+
|
|
14
|
+
// returns the current source file
|
|
15
|
+
export function useSourceFile(): SourceFileContext | undefined {
|
|
16
|
+
return core.useContext(SourceFileContext) as SourceFileContext;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// properties fro creating a C# source file
|
|
20
|
+
export interface SourceFileProps {
|
|
21
|
+
path: string;
|
|
22
|
+
using?: Array<string>;
|
|
23
|
+
children?: core.Children;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// a C# source file. exists within the context of a namespace
|
|
27
|
+
// contains using statements and declarations
|
|
28
|
+
export function SourceFile(props: SourceFileProps) {
|
|
29
|
+
const namespaceCtx = useNamespace();
|
|
30
|
+
|
|
31
|
+
if (!namespaceCtx) {
|
|
32
|
+
throw new Error("SourceFile must be declared inside a namespace");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const using: Array<string> = core.reactive(new Array<string>());
|
|
36
|
+
if (props.using) {
|
|
37
|
+
using.push(...props.using);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// adds the specified namespace to the array of using statements.
|
|
41
|
+
// called via SourceFileContext.addUsing when resolving refkeys.
|
|
42
|
+
function addUsing(namespace: string): void {
|
|
43
|
+
if (!using.includes(namespace)) {
|
|
44
|
+
using.push(namespace);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const sourceFileCtx: SourceFileContext = {
|
|
49
|
+
addUsing,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return <core.SourceFile path={props.path} filetype="cs" reference={Reference}>
|
|
53
|
+
<SourceFileContext.Provider value={sourceFileCtx}>
|
|
54
|
+
<core.Scope name={props.path} kind="source-file">
|
|
55
|
+
{using.length > 0 ? (
|
|
56
|
+
<>
|
|
57
|
+
<UsingDirective namespaces={using} />{"\n"}
|
|
58
|
+
</>
|
|
59
|
+
) : undefined}namespace {namespaceCtx.name}{!props.children && " {}"}{props.children &&
|
|
60
|
+
<>
|
|
61
|
+
{"\n{"}
|
|
62
|
+
{props.children}
|
|
63
|
+
{"}"}
|
|
64
|
+
</>
|
|
65
|
+
}
|
|
66
|
+
</core.Scope>
|
|
67
|
+
</SourceFileContext.Provider>
|
|
68
|
+
</core.SourceFile>;
|
|
69
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as core from "@alloy-js/core";
|
|
2
|
+
|
|
3
|
+
export interface UsingDirectiveProps {
|
|
4
|
+
namespaces: Array<string>;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// one ore more C# using directives
|
|
8
|
+
export function UsingDirective(props: UsingDirectiveProps) {
|
|
9
|
+
// we need core.memo here so that the contents are in a reactive context.
|
|
10
|
+
// the values for namespaces are reactive thus we need to observe any changes.
|
|
11
|
+
return core.memo(() => {
|
|
12
|
+
props.namespaces.sort();
|
|
13
|
+
return core
|
|
14
|
+
.mapJoin(props.namespaces, (namespace) => {
|
|
15
|
+
return `using ${namespace};`;
|
|
16
|
+
})
|
|
17
|
+
.join("");
|
|
18
|
+
});
|
|
19
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "./Class.js";
|
|
2
|
+
export * from "./Declaration.js";
|
|
3
|
+
export * from "./Enum.js";
|
|
4
|
+
export * from "./Name.js";
|
|
5
|
+
export * from "./Namespace.js";
|
|
6
|
+
export * from "./Parameters.js";
|
|
7
|
+
export * from "./ProjectDirectory.js";
|
|
8
|
+
export * from "./Reference.js";
|
|
9
|
+
export * from "./SourceFile.js";
|
|
10
|
+
export * from "./UsingDirective.js";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as core from "@alloy-js/core";
|
|
2
|
+
import * as base from "../index.js";
|
|
3
|
+
|
|
4
|
+
export const Class = core.stc(base.Class);
|
|
5
|
+
export const ClassConstructor = core.stc(base.ClassConstructor);
|
|
6
|
+
export const ClassMember = core.stc(base.ClassMember);
|
|
7
|
+
export const ClassMethod = core.stc(base.ClassMethod);
|
|
8
|
+
export const Enum = core.stc(base.Enum);
|
|
9
|
+
export const EnumMember = core.stc(base.EnumMember);
|
|
10
|
+
export const Parameter = core.stc(base.Parameter);
|
|
11
|
+
export const Parameters = core.stc(base.Parameters);
|
|
12
|
+
export const ProjectDirectory = core.stc(base.ProjectDirectory);
|
|
13
|
+
export const UsingDirective = core.stc(base.UsingDirective);
|
package/src/index.ts
ADDED
package/src/modifiers.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// the possible C# access modifiers
|
|
2
|
+
// https://learn.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers
|
|
3
|
+
export type AccessModifier =
|
|
4
|
+
| "public"
|
|
5
|
+
| "protected"
|
|
6
|
+
| "private"
|
|
7
|
+
| "internal"
|
|
8
|
+
| "protected-internal"
|
|
9
|
+
| "private-protected"
|
|
10
|
+
| "file";
|
|
11
|
+
|
|
12
|
+
// maps the above access modifier value to its C# syntax.
|
|
13
|
+
// note that the C# keyword includes a trailing space
|
|
14
|
+
const accessModifierLookup: Record<AccessModifier, string> = {
|
|
15
|
+
public: "public ",
|
|
16
|
+
protected: "protected ",
|
|
17
|
+
private: "private ",
|
|
18
|
+
internal: "internal ",
|
|
19
|
+
"protected-internal": "protected internal ",
|
|
20
|
+
"private-protected": "private protected ",
|
|
21
|
+
file: "file ",
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// returns the C# syntax for the specified access modifier.
|
|
25
|
+
// if no access modifier is specified, the empty string is returned.
|
|
26
|
+
export function getAccessModifier(accessModifier?: AccessModifier): string {
|
|
27
|
+
return accessModifier ? accessModifierLookup[accessModifier] : "";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type MethodModifier = "abstract" | "sealed" | "static" | "virtual";
|
|
31
|
+
|
|
32
|
+
// maps the above method modifier value to its C# syntax.
|
|
33
|
+
// note that the C# keyword includes a trailing space
|
|
34
|
+
const methodModifierLookup: Record<MethodModifier, string> = {
|
|
35
|
+
abstract: "abstract ",
|
|
36
|
+
sealed: "sealed ",
|
|
37
|
+
static: "static ",
|
|
38
|
+
virtual: "virtual ",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// returns the C# syntax for the specified method modifier.
|
|
42
|
+
// if no method modifier is specified, the empty string is returned.
|
|
43
|
+
export function getMethodModifier(methodModifier?: MethodModifier): string {
|
|
44
|
+
return methodModifier ? methodModifierLookup[methodModifier] : "";
|
|
45
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as core from "@alloy-js/core";
|
|
2
|
+
import * as changecase from "change-case";
|
|
3
|
+
|
|
4
|
+
// the context in which the name policy should be applied
|
|
5
|
+
export type CSharpElements =
|
|
6
|
+
| "class"
|
|
7
|
+
| "constant"
|
|
8
|
+
| "enum"
|
|
9
|
+
| "enum-member"
|
|
10
|
+
| "function"
|
|
11
|
+
| "interface"
|
|
12
|
+
| "class-member-private"
|
|
13
|
+
| "class-member-public"
|
|
14
|
+
| "class-method"
|
|
15
|
+
| "parameter"
|
|
16
|
+
| "type-parameter";
|
|
17
|
+
|
|
18
|
+
// creates the C# naming policy
|
|
19
|
+
export function createCSharpNamePolicy(): core.NamePolicy<CSharpElements> {
|
|
20
|
+
return core.createNamePolicy((name, element) => {
|
|
21
|
+
switch (element) {
|
|
22
|
+
case "class":
|
|
23
|
+
case "enum":
|
|
24
|
+
case "enum-member":
|
|
25
|
+
case "interface":
|
|
26
|
+
case "class-member-public":
|
|
27
|
+
case "class-method":
|
|
28
|
+
case "type-parameter":
|
|
29
|
+
return changecase.pascalCase(name);
|
|
30
|
+
case "constant":
|
|
31
|
+
return changecase.constantCase(name);
|
|
32
|
+
default:
|
|
33
|
+
return changecase.camelCase(name);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// gets the active C# naming policy
|
|
39
|
+
export function useCSharpNamePolicy(): core.NamePolicy<CSharpElements> {
|
|
40
|
+
return core.useNamePolicy();
|
|
41
|
+
}
|