@tsonic/backend 0.0.1
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/package.json +34 -0
- package/src/build-orchestrator.ts +215 -0
- package/src/dotnet.test.ts +50 -0
- package/src/dotnet.ts +101 -0
- package/src/index.ts +28 -0
- package/src/program-generator.test.ts +63 -0
- package/src/program-generator.ts +33 -0
- package/src/project-generator.test.ts +130 -0
- package/src/project-generator.ts +245 -0
- package/src/types.ts +150 -0
- package/tsconfig.json +14 -0
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tsonic/backend",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": ".NET build orchestration for Tsonic compiler",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc -b",
|
|
16
|
+
"clean": "rm -rf dist *.tsbuildinfo",
|
|
17
|
+
"test": "mocha 'dist/**/*.test.js'",
|
|
18
|
+
"test:watch": "mocha 'dist/**/*.test.js' --watch"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@tsonic/emitter": "0.0.1",
|
|
22
|
+
"@tsonic/frontend": "0.0.1"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/chai": "5.2.2",
|
|
26
|
+
"@types/mocha": "10.0.10",
|
|
27
|
+
"@types/node": "20.14.0",
|
|
28
|
+
"chai": "5.3.3",
|
|
29
|
+
"mocha": "11.7.2"
|
|
30
|
+
},
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=18.0.0"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main build orchestration - coordinates the entire NativeAOT build process
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createHash } from "crypto";
|
|
6
|
+
import {
|
|
7
|
+
mkdirSync,
|
|
8
|
+
writeFileSync,
|
|
9
|
+
copyFileSync,
|
|
10
|
+
rmSync,
|
|
11
|
+
chmodSync,
|
|
12
|
+
existsSync,
|
|
13
|
+
readdirSync,
|
|
14
|
+
} from "fs";
|
|
15
|
+
import { join, dirname } from "path";
|
|
16
|
+
import {
|
|
17
|
+
BuildOptions,
|
|
18
|
+
BuildResult,
|
|
19
|
+
BuildConfig,
|
|
20
|
+
EntryInfo,
|
|
21
|
+
NuGetPackage,
|
|
22
|
+
} from "./types.js";
|
|
23
|
+
import { generateCsproj } from "./project-generator.js";
|
|
24
|
+
import { generateProgramCs } from "./program-generator.js";
|
|
25
|
+
import { checkDotnetInstalled, detectRid, publishNativeAot } from "./dotnet.js";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create unique build directory
|
|
29
|
+
*/
|
|
30
|
+
const createBuildDir = (entryFile: string): string => {
|
|
31
|
+
const hash = createHash("md5").update(entryFile).digest("hex").slice(0, 8);
|
|
32
|
+
const buildDir = join(process.cwd(), ".tsonic", "build", hash);
|
|
33
|
+
mkdirSync(buildDir, { recursive: true });
|
|
34
|
+
return buildDir;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Copy generated C# files to build directory
|
|
39
|
+
*/
|
|
40
|
+
const copyGeneratedFiles = (
|
|
41
|
+
emittedFiles: Map<string, string>,
|
|
42
|
+
buildDir: string
|
|
43
|
+
): void => {
|
|
44
|
+
for (const [tsPath, csContent] of emittedFiles) {
|
|
45
|
+
// src/models/User.ts → <buildDir>/src/models/User.cs
|
|
46
|
+
const csPath = tsPath.replace(/\.ts$/, ".cs");
|
|
47
|
+
const fullPath = join(buildDir, csPath);
|
|
48
|
+
|
|
49
|
+
mkdirSync(dirname(fullPath), { recursive: true });
|
|
50
|
+
writeFileSync(fullPath, csContent, "utf-8");
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Find project .csproj file in current directory
|
|
56
|
+
*/
|
|
57
|
+
const findProjectCsproj = (): string | null => {
|
|
58
|
+
const cwd = process.cwd();
|
|
59
|
+
// Look for *.csproj in current directory
|
|
60
|
+
const files = readdirSync(cwd);
|
|
61
|
+
const csprojFile = files.find((f) => f.endsWith(".csproj"));
|
|
62
|
+
return csprojFile ? join(cwd, csprojFile) : null;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get output binary name for platform
|
|
67
|
+
*/
|
|
68
|
+
const getOutputBinaryName = (outputName: string): string => {
|
|
69
|
+
return process.platform === "win32" ? `${outputName}.exe` : outputName;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Copy output binary to final location
|
|
74
|
+
*/
|
|
75
|
+
const copyOutputBinary = (
|
|
76
|
+
buildDir: string,
|
|
77
|
+
rid: string,
|
|
78
|
+
outputPath: string,
|
|
79
|
+
outputName: string
|
|
80
|
+
): void => {
|
|
81
|
+
const publishDir = join(buildDir, "bin/Release/net8.0", rid, "publish");
|
|
82
|
+
const binaryName = getOutputBinaryName(outputName);
|
|
83
|
+
const binaryPath = join(publishDir, binaryName);
|
|
84
|
+
|
|
85
|
+
if (!existsSync(binaryPath)) {
|
|
86
|
+
throw new Error(`Output binary not found at ${binaryPath}`);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
copyFileSync(binaryPath, outputPath);
|
|
90
|
+
|
|
91
|
+
// Make executable on Unix
|
|
92
|
+
if (process.platform !== "win32") {
|
|
93
|
+
chmodSync(outputPath, 0o755);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Clean build directory
|
|
99
|
+
*/
|
|
100
|
+
const cleanBuild = (buildDir: string, keepTemp: boolean): void => {
|
|
101
|
+
if (!keepTemp) {
|
|
102
|
+
rmSync(buildDir, { recursive: true, force: true });
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Build NativeAOT executable from C# files
|
|
108
|
+
*/
|
|
109
|
+
export const buildNativeAot = (
|
|
110
|
+
emittedFiles: Map<string, string>,
|
|
111
|
+
entryInfo: EntryInfo,
|
|
112
|
+
options: BuildOptions
|
|
113
|
+
): BuildResult => {
|
|
114
|
+
let buildDir: string | undefined;
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
// Check dotnet is installed
|
|
118
|
+
const dotnetCheck = checkDotnetInstalled();
|
|
119
|
+
if (!dotnetCheck.ok) {
|
|
120
|
+
return {
|
|
121
|
+
ok: false,
|
|
122
|
+
error: dotnetCheck.error,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Create build directory
|
|
127
|
+
buildDir = createBuildDir(Array.from(emittedFiles.keys())[0] || "main");
|
|
128
|
+
|
|
129
|
+
// Copy generated C# files
|
|
130
|
+
copyGeneratedFiles(emittedFiles, buildDir);
|
|
131
|
+
|
|
132
|
+
// Generate Program.cs if needed
|
|
133
|
+
if (entryInfo.needsProgram) {
|
|
134
|
+
const programCs = generateProgramCs(entryInfo);
|
|
135
|
+
writeFileSync(join(buildDir, "Program.cs"), programCs, "utf-8");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Use existing project .csproj if available, otherwise generate one
|
|
139
|
+
const projectCsproj = findProjectCsproj();
|
|
140
|
+
if (projectCsproj) {
|
|
141
|
+
// Copy existing .csproj to build directory (preserves user edits)
|
|
142
|
+
const csprojFilename = projectCsproj.split("/").pop() || "project.csproj";
|
|
143
|
+
copyFileSync(projectCsproj, join(buildDir, csprojFilename));
|
|
144
|
+
} else {
|
|
145
|
+
// Generate temporary .csproj for build
|
|
146
|
+
// Tsonic.Runtime is ALWAYS required (for unions, typeof, structural)
|
|
147
|
+
// Tsonic.JSRuntime only when mode: "js" (for JS semantics)
|
|
148
|
+
const packages: NuGetPackage[] = [
|
|
149
|
+
{ name: "Tsonic.Runtime", version: "0.0.1" },
|
|
150
|
+
];
|
|
151
|
+
if (entryInfo.runtime === "js") {
|
|
152
|
+
packages.push({ name: "Tsonic.JSRuntime", version: "0.0.1" });
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const buildConfig: BuildConfig = {
|
|
156
|
+
rootNamespace: options.namespace,
|
|
157
|
+
outputName: options.outputName || "tsonic",
|
|
158
|
+
dotnetVersion: options.dotnetVersion || "net10.0",
|
|
159
|
+
packages,
|
|
160
|
+
outputConfig: {
|
|
161
|
+
type: "executable",
|
|
162
|
+
nativeAot: true,
|
|
163
|
+
singleFile: true,
|
|
164
|
+
trimmed: true,
|
|
165
|
+
stripSymbols: options.stripSymbols ?? true,
|
|
166
|
+
optimization: options.optimizationPreference || "Speed",
|
|
167
|
+
invariantGlobalization: true,
|
|
168
|
+
selfContained: true,
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const csprojContent = generateCsproj(buildConfig);
|
|
173
|
+
writeFileSync(join(buildDir, "tsonic.csproj"), csprojContent, "utf-8");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Detect RID
|
|
177
|
+
const rid = options.rid || detectRid();
|
|
178
|
+
|
|
179
|
+
// Execute dotnet publish
|
|
180
|
+
const publishResult = publishNativeAot(buildDir, rid);
|
|
181
|
+
if (!publishResult.ok) {
|
|
182
|
+
return {
|
|
183
|
+
ok: false,
|
|
184
|
+
error: publishResult.error,
|
|
185
|
+
buildDir,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Copy output binary
|
|
190
|
+
const outputPath = options.outputName
|
|
191
|
+
? `./${getOutputBinaryName(options.outputName)}`
|
|
192
|
+
: "./tsonic-app";
|
|
193
|
+
copyOutputBinary(buildDir, rid, outputPath, options.outputName || "tsonic");
|
|
194
|
+
|
|
195
|
+
// Cleanup if requested
|
|
196
|
+
cleanBuild(buildDir, options.keepTemp ?? false);
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
ok: true,
|
|
200
|
+
outputPath,
|
|
201
|
+
buildDir,
|
|
202
|
+
};
|
|
203
|
+
} catch (error) {
|
|
204
|
+
if (buildDir) {
|
|
205
|
+
cleanBuild(buildDir, false);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return {
|
|
209
|
+
ok: false,
|
|
210
|
+
error:
|
|
211
|
+
error instanceof Error ? error.message : "Unknown build error occurred",
|
|
212
|
+
buildDir,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for dotnet CLI wrapper
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it } from "mocha";
|
|
6
|
+
import { expect } from "chai";
|
|
7
|
+
import { detectRid } from "./dotnet.js";
|
|
8
|
+
|
|
9
|
+
describe("Dotnet CLI Wrapper", () => {
|
|
10
|
+
describe("detectRid", () => {
|
|
11
|
+
it("should return a valid runtime identifier", () => {
|
|
12
|
+
const rid = detectRid();
|
|
13
|
+
|
|
14
|
+
// Should match one of the known RID patterns
|
|
15
|
+
const validRids = [
|
|
16
|
+
"osx-x64",
|
|
17
|
+
"osx-arm64",
|
|
18
|
+
"linux-x64",
|
|
19
|
+
"linux-arm64",
|
|
20
|
+
"win-x64",
|
|
21
|
+
"win-arm64",
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
expect(validRids).to.include(rid);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("should detect current platform RID", () => {
|
|
28
|
+
const rid = detectRid();
|
|
29
|
+
const platform = process.platform;
|
|
30
|
+
const arch = process.arch;
|
|
31
|
+
|
|
32
|
+
if (platform === "darwin") {
|
|
33
|
+
expect(rid).to.match(/^osx-/);
|
|
34
|
+
} else if (platform === "linux") {
|
|
35
|
+
expect(rid).to.match(/^linux-/);
|
|
36
|
+
} else if (platform === "win32") {
|
|
37
|
+
expect(rid).to.match(/^win-/);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (arch === "x64") {
|
|
41
|
+
expect(rid).to.include("x64");
|
|
42
|
+
} else if (arch === "arm64") {
|
|
43
|
+
expect(rid).to.include("arm64");
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Note: checkDotnetInstalled and publishNativeAot are integration tests
|
|
49
|
+
// that require dotnet to be installed, so we skip them in unit tests
|
|
50
|
+
});
|
package/src/dotnet.ts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dotnet CLI wrapper for executing build commands
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { spawnSync } from "child_process";
|
|
6
|
+
import { DotnetResult } from "./types.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Check if dotnet CLI is available
|
|
10
|
+
*/
|
|
11
|
+
export const checkDotnetInstalled = (): DotnetResult => {
|
|
12
|
+
const result = spawnSync("dotnet", ["--version"], {
|
|
13
|
+
encoding: "utf-8",
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
if (result.error) {
|
|
17
|
+
return {
|
|
18
|
+
ok: false,
|
|
19
|
+
error: ".NET SDK not found. Install from https://dot.net",
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (result.status !== 0) {
|
|
24
|
+
return {
|
|
25
|
+
ok: false,
|
|
26
|
+
error: "dotnet command failed",
|
|
27
|
+
stderr: result.stderr,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
ok: true,
|
|
33
|
+
stdout: result.stdout.trim(),
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Detect runtime identifier for current platform
|
|
39
|
+
*/
|
|
40
|
+
export const detectRid = (): string => {
|
|
41
|
+
const platform = process.platform;
|
|
42
|
+
const arch = process.arch;
|
|
43
|
+
|
|
44
|
+
const ridMap: Record<string, string> = {
|
|
45
|
+
"darwin-x64": "osx-x64",
|
|
46
|
+
"darwin-arm64": "osx-arm64",
|
|
47
|
+
"linux-x64": "linux-x64",
|
|
48
|
+
"linux-arm64": "linux-arm64",
|
|
49
|
+
"win32-x64": "win-x64",
|
|
50
|
+
"win32-arm64": "win-arm64",
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const key = `${platform}-${arch}`;
|
|
54
|
+
return ridMap[key] || "linux-x64";
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Execute dotnet publish with NativeAOT
|
|
59
|
+
*/
|
|
60
|
+
export const publishNativeAot = (
|
|
61
|
+
buildDir: string,
|
|
62
|
+
rid: string
|
|
63
|
+
): DotnetResult => {
|
|
64
|
+
const args = [
|
|
65
|
+
"publish",
|
|
66
|
+
"tsonic.csproj",
|
|
67
|
+
"-c",
|
|
68
|
+
"Release",
|
|
69
|
+
"-r",
|
|
70
|
+
rid,
|
|
71
|
+
"-p:PublishAot=true",
|
|
72
|
+
"-p:PublishSingleFile=true",
|
|
73
|
+
"--self-contained",
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
const result = spawnSync("dotnet", args, {
|
|
77
|
+
cwd: buildDir,
|
|
78
|
+
encoding: "utf-8",
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
if (result.error) {
|
|
82
|
+
return {
|
|
83
|
+
ok: false,
|
|
84
|
+
error: `Failed to execute dotnet: ${result.error.message}`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (result.status !== 0) {
|
|
89
|
+
return {
|
|
90
|
+
ok: false,
|
|
91
|
+
error: `dotnet publish failed with code ${result.status}`,
|
|
92
|
+
stdout: result.stdout,
|
|
93
|
+
stderr: result.stderr,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
ok: true,
|
|
99
|
+
stdout: result.stdout,
|
|
100
|
+
};
|
|
101
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tsonic Backend - .NET build orchestration
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Export main build function
|
|
6
|
+
export { buildNativeAot } from "./build-orchestrator.js";
|
|
7
|
+
|
|
8
|
+
// Export types
|
|
9
|
+
export type {
|
|
10
|
+
BuildOptions,
|
|
11
|
+
BuildResult,
|
|
12
|
+
BuildConfig,
|
|
13
|
+
EntryInfo,
|
|
14
|
+
NuGetPackage,
|
|
15
|
+
DotnetResult,
|
|
16
|
+
OutputType,
|
|
17
|
+
OutputConfig,
|
|
18
|
+
ExecutableConfig,
|
|
19
|
+
LibraryConfig,
|
|
20
|
+
ConsoleAppConfig,
|
|
21
|
+
PackageMetadata,
|
|
22
|
+
AssemblyReference,
|
|
23
|
+
} from "./types.js";
|
|
24
|
+
|
|
25
|
+
// Export utilities
|
|
26
|
+
export { checkDotnetInstalled, detectRid } from "./dotnet.js";
|
|
27
|
+
export { generateCsproj } from "./project-generator.js";
|
|
28
|
+
export { generateProgramCs } from "./program-generator.js";
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Program.cs generation
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it } from "mocha";
|
|
6
|
+
import { expect } from "chai";
|
|
7
|
+
import { generateProgramCs } from "./program-generator.js";
|
|
8
|
+
import { EntryInfo } from "./types.js";
|
|
9
|
+
|
|
10
|
+
describe("Program Generator", () => {
|
|
11
|
+
describe("generateProgramCs", () => {
|
|
12
|
+
it("should generate synchronous Main method", () => {
|
|
13
|
+
const entryInfo: EntryInfo = {
|
|
14
|
+
namespace: "MyApp",
|
|
15
|
+
className: "main",
|
|
16
|
+
methodName: "start",
|
|
17
|
+
isAsync: false,
|
|
18
|
+
needsProgram: true,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const result = generateProgramCs(entryInfo);
|
|
22
|
+
|
|
23
|
+
expect(result).to.include("public static void Main(string[] args)");
|
|
24
|
+
expect(result).to.include("main.start();");
|
|
25
|
+
expect(result).to.not.include("await");
|
|
26
|
+
expect(result).to.not.include("async");
|
|
27
|
+
expect(result).to.include("using MyApp;");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("should generate async Main method", () => {
|
|
31
|
+
const entryInfo: EntryInfo = {
|
|
32
|
+
namespace: "MyApp.Services",
|
|
33
|
+
className: "main",
|
|
34
|
+
methodName: "run",
|
|
35
|
+
isAsync: true,
|
|
36
|
+
needsProgram: true,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const result = generateProgramCs(entryInfo);
|
|
40
|
+
|
|
41
|
+
expect(result).to.include("public static async Task Main(string[] args)");
|
|
42
|
+
expect(result).to.include("await main.run();");
|
|
43
|
+
expect(result).to.include("using MyApp.Services;");
|
|
44
|
+
expect(result).to.include("using System.Threading.Tasks;");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should include required using statements", () => {
|
|
48
|
+
const entryInfo: EntryInfo = {
|
|
49
|
+
namespace: "Test",
|
|
50
|
+
className: "Program",
|
|
51
|
+
methodName: "Main",
|
|
52
|
+
isAsync: false,
|
|
53
|
+
needsProgram: true,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const result = generateProgramCs(entryInfo);
|
|
57
|
+
|
|
58
|
+
expect(result).to.include("using System;");
|
|
59
|
+
expect(result).to.include("using Tsonic.Runtime;");
|
|
60
|
+
expect(result).to.include("using Test;");
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Program.cs generation for entry point wrapper
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { EntryInfo } from "./types.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Generate Program.cs content with Main method
|
|
9
|
+
*/
|
|
10
|
+
export const generateProgramCs = (entryInfo: EntryInfo): string => {
|
|
11
|
+
const returnType = entryInfo.isAsync ? "async Task" : "void";
|
|
12
|
+
const awaitKeyword = entryInfo.isAsync ? "await " : "";
|
|
13
|
+
|
|
14
|
+
const usings = ["using System;", "using System.Threading.Tasks;"];
|
|
15
|
+
|
|
16
|
+
// Only include Tsonic.Runtime for js runtime mode
|
|
17
|
+
if (entryInfo.runtime !== "dotnet") {
|
|
18
|
+
usings.push("using Tsonic.Runtime;");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
usings.push(`using ${entryInfo.namespace};`);
|
|
22
|
+
|
|
23
|
+
return `${usings.join("\n")}
|
|
24
|
+
|
|
25
|
+
public static class Program
|
|
26
|
+
{
|
|
27
|
+
public static ${returnType} Main(string[] args)
|
|
28
|
+
{
|
|
29
|
+
${awaitKeyword}${entryInfo.className}.${entryInfo.methodName}();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for .csproj generation
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it } from "mocha";
|
|
6
|
+
import { expect } from "chai";
|
|
7
|
+
import { generateCsproj } from "./project-generator.js";
|
|
8
|
+
import { BuildConfig } from "./types.js";
|
|
9
|
+
|
|
10
|
+
describe("Project Generator", () => {
|
|
11
|
+
describe("generateCsproj", () => {
|
|
12
|
+
it("should generate basic executable .csproj without packages", () => {
|
|
13
|
+
const config: BuildConfig = {
|
|
14
|
+
rootNamespace: "TestApp",
|
|
15
|
+
outputName: "test",
|
|
16
|
+
dotnetVersion: "net10.0",
|
|
17
|
+
packages: [],
|
|
18
|
+
outputConfig: {
|
|
19
|
+
type: "executable",
|
|
20
|
+
nativeAot: true,
|
|
21
|
+
singleFile: true,
|
|
22
|
+
trimmed: true,
|
|
23
|
+
stripSymbols: true,
|
|
24
|
+
optimization: "Speed",
|
|
25
|
+
invariantGlobalization: true,
|
|
26
|
+
selfContained: true,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const result = generateCsproj(config);
|
|
31
|
+
|
|
32
|
+
expect(result).to.include('<Project Sdk="Microsoft.NET.Sdk">');
|
|
33
|
+
expect(result).to.include("<TargetFramework>net10.0</TargetFramework>");
|
|
34
|
+
expect(result).to.include("<RootNamespace>TestApp</RootNamespace>");
|
|
35
|
+
expect(result).to.include("<AssemblyName>test</AssemblyName>");
|
|
36
|
+
expect(result).to.include("<PublishAot>true</PublishAot>");
|
|
37
|
+
expect(result).to.include(
|
|
38
|
+
"<OptimizationPreference>Speed</OptimizationPreference>"
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should include package references when provided", () => {
|
|
43
|
+
const config: BuildConfig = {
|
|
44
|
+
rootNamespace: "TestApp",
|
|
45
|
+
outputName: "test",
|
|
46
|
+
dotnetVersion: "net10.0",
|
|
47
|
+
packages: [
|
|
48
|
+
{ name: "System.Text.Json", version: "8.0.0" },
|
|
49
|
+
{ name: "Newtonsoft.Json", version: "13.0.3" },
|
|
50
|
+
],
|
|
51
|
+
outputConfig: {
|
|
52
|
+
type: "executable",
|
|
53
|
+
nativeAot: true,
|
|
54
|
+
singleFile: true,
|
|
55
|
+
trimmed: true,
|
|
56
|
+
stripSymbols: true,
|
|
57
|
+
optimization: "Size",
|
|
58
|
+
invariantGlobalization: true,
|
|
59
|
+
selfContained: true,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const result = generateCsproj(config);
|
|
64
|
+
|
|
65
|
+
expect(result).to.include(
|
|
66
|
+
'<PackageReference Include="System.Text.Json" Version="8.0.0"'
|
|
67
|
+
);
|
|
68
|
+
expect(result).to.include(
|
|
69
|
+
'<PackageReference Include="Newtonsoft.Json" Version="13.0.3"'
|
|
70
|
+
);
|
|
71
|
+
expect(result).to.include(
|
|
72
|
+
"<OptimizationPreference>Size</OptimizationPreference>"
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("should set invariant globalization correctly", () => {
|
|
77
|
+
const config: BuildConfig = {
|
|
78
|
+
rootNamespace: "TestApp",
|
|
79
|
+
outputName: "test",
|
|
80
|
+
dotnetVersion: "net10.0",
|
|
81
|
+
packages: [],
|
|
82
|
+
outputConfig: {
|
|
83
|
+
type: "executable",
|
|
84
|
+
nativeAot: true,
|
|
85
|
+
singleFile: true,
|
|
86
|
+
trimmed: true,
|
|
87
|
+
stripSymbols: false,
|
|
88
|
+
optimization: "Speed",
|
|
89
|
+
invariantGlobalization: false,
|
|
90
|
+
selfContained: true,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const result = generateCsproj(config);
|
|
95
|
+
|
|
96
|
+
expect(result).to.include(
|
|
97
|
+
"<InvariantGlobalization>false</InvariantGlobalization>"
|
|
98
|
+
);
|
|
99
|
+
expect(result).to.include("<StripSymbols>false</StripSymbols>");
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("should generate library .csproj", () => {
|
|
103
|
+
const config: BuildConfig = {
|
|
104
|
+
rootNamespace: "TestLib",
|
|
105
|
+
outputName: "testlib",
|
|
106
|
+
dotnetVersion: "net10.0",
|
|
107
|
+
packages: [],
|
|
108
|
+
outputConfig: {
|
|
109
|
+
type: "library",
|
|
110
|
+
targetFrameworks: ["net8.0", "net9.0"],
|
|
111
|
+
generateDocumentation: true,
|
|
112
|
+
includeSymbols: true,
|
|
113
|
+
packable: false,
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const result = generateCsproj(config);
|
|
118
|
+
|
|
119
|
+
expect(result).to.include("<OutputType>Library</OutputType>");
|
|
120
|
+
expect(result).to.include(
|
|
121
|
+
"<TargetFrameworks>net8.0;net9.0</TargetFrameworks>"
|
|
122
|
+
);
|
|
123
|
+
expect(result).to.include(
|
|
124
|
+
"<GenerateDocumentationFile>true</GenerateDocumentationFile>"
|
|
125
|
+
);
|
|
126
|
+
expect(result).to.include("<DebugType>embedded</DebugType>");
|
|
127
|
+
expect(result).to.include("<IsPackable>false</IsPackable>");
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* .csproj file generation for multiple output types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
BuildConfig,
|
|
7
|
+
NuGetPackage,
|
|
8
|
+
OutputConfig,
|
|
9
|
+
ExecutableConfig,
|
|
10
|
+
LibraryConfig,
|
|
11
|
+
ConsoleAppConfig,
|
|
12
|
+
PackageMetadata,
|
|
13
|
+
AssemblyReference,
|
|
14
|
+
} from "./types.js";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Generate package references XML
|
|
18
|
+
*/
|
|
19
|
+
const formatPackageReferences = (packages: readonly NuGetPackage[]): string => {
|
|
20
|
+
if (packages.length === 0) {
|
|
21
|
+
return "";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const refs = packages
|
|
25
|
+
.map(
|
|
26
|
+
(pkg) =>
|
|
27
|
+
` <PackageReference Include="${pkg.name}" Version="${pkg.version}" />`
|
|
28
|
+
)
|
|
29
|
+
.join("\n");
|
|
30
|
+
|
|
31
|
+
return `
|
|
32
|
+
<ItemGroup>
|
|
33
|
+
${refs}
|
|
34
|
+
</ItemGroup>`;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Generate assembly references XML (for DLL files)
|
|
39
|
+
*/
|
|
40
|
+
const formatAssemblyReferences = (
|
|
41
|
+
refs: readonly AssemblyReference[]
|
|
42
|
+
): string => {
|
|
43
|
+
if (refs.length === 0) {
|
|
44
|
+
return "";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const refElements = refs
|
|
48
|
+
.map(
|
|
49
|
+
(ref) =>
|
|
50
|
+
` <Reference Include="${ref.name}">
|
|
51
|
+
<HintPath>${ref.hintPath}</HintPath>
|
|
52
|
+
</Reference>`
|
|
53
|
+
)
|
|
54
|
+
.join("\n");
|
|
55
|
+
|
|
56
|
+
return `
|
|
57
|
+
<ItemGroup>
|
|
58
|
+
${refElements}
|
|
59
|
+
</ItemGroup>`;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Capitalize first letter
|
|
64
|
+
*/
|
|
65
|
+
const capitalizeFirst = (str: string): string => {
|
|
66
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Generate NuGet package metadata properties
|
|
71
|
+
*/
|
|
72
|
+
const generatePackageMetadata = (metadata: PackageMetadata): string => {
|
|
73
|
+
const authors = metadata.authors.join(";");
|
|
74
|
+
const tags = metadata.tags?.join(";") || "";
|
|
75
|
+
|
|
76
|
+
return `
|
|
77
|
+
<PackageId>${metadata.id}</PackageId>
|
|
78
|
+
<Version>${metadata.version}</Version>
|
|
79
|
+
<Authors>${authors}</Authors>
|
|
80
|
+
<Description>${metadata.description}</Description>${metadata.projectUrl ? `\n <PackageProjectUrl>${metadata.projectUrl}</PackageProjectUrl>` : ""}${metadata.license ? `\n <PackageLicenseExpression>${metadata.license}</PackageLicenseExpression>` : ""}${tags ? `\n <PackageTags>${tags}</PackageTags>` : ""}`;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Generate property group for executable output
|
|
85
|
+
*/
|
|
86
|
+
const generateExecutableProperties = (
|
|
87
|
+
config: BuildConfig,
|
|
88
|
+
execConfig: ExecutableConfig
|
|
89
|
+
): string => {
|
|
90
|
+
const nativeAotSettings = execConfig.nativeAot
|
|
91
|
+
? `
|
|
92
|
+
<!-- NativeAOT settings -->
|
|
93
|
+
<PublishAot>true</PublishAot>
|
|
94
|
+
<PublishSingleFile>${execConfig.singleFile}</PublishSingleFile>
|
|
95
|
+
<PublishTrimmed>${execConfig.trimmed}</PublishTrimmed>
|
|
96
|
+
<InvariantGlobalization>${execConfig.invariantGlobalization}</InvariantGlobalization>
|
|
97
|
+
<StripSymbols>${execConfig.stripSymbols}</StripSymbols>
|
|
98
|
+
|
|
99
|
+
<!-- Optimization -->
|
|
100
|
+
<OptimizationPreference>${capitalizeFirst(execConfig.optimization)}</OptimizationPreference>
|
|
101
|
+
<IlcOptimizationPreference>${capitalizeFirst(execConfig.optimization)}</IlcOptimizationPreference>`
|
|
102
|
+
: `
|
|
103
|
+
<PublishSingleFile>${execConfig.singleFile}</PublishSingleFile>
|
|
104
|
+
<SelfContained>${execConfig.selfContained}</SelfContained>`;
|
|
105
|
+
|
|
106
|
+
return ` <PropertyGroup>
|
|
107
|
+
<OutputType>Exe</OutputType>
|
|
108
|
+
<TargetFramework>${config.dotnetVersion}</TargetFramework>
|
|
109
|
+
<RootNamespace>${config.rootNamespace}</RootNamespace>
|
|
110
|
+
<AssemblyName>${config.outputName}</AssemblyName>
|
|
111
|
+
<Nullable>enable</Nullable>
|
|
112
|
+
<ImplicitUsings>false</ImplicitUsings>${nativeAotSettings}
|
|
113
|
+
</PropertyGroup>`;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Generate property group for library output
|
|
118
|
+
*/
|
|
119
|
+
const generateLibraryProperties = (
|
|
120
|
+
config: BuildConfig,
|
|
121
|
+
libConfig: LibraryConfig
|
|
122
|
+
): string => {
|
|
123
|
+
const targetFrameworks = libConfig.targetFrameworks.join(";");
|
|
124
|
+
const isMultiTarget = libConfig.targetFrameworks.length > 1;
|
|
125
|
+
const targetProp = isMultiTarget
|
|
126
|
+
? `<TargetFrameworks>${targetFrameworks}</TargetFrameworks>`
|
|
127
|
+
: `<TargetFramework>${libConfig.targetFrameworks[0]}</TargetFramework>`;
|
|
128
|
+
|
|
129
|
+
const docSettings = libConfig.generateDocumentation
|
|
130
|
+
? `
|
|
131
|
+
<GenerateDocumentationFile>true</GenerateDocumentationFile>`
|
|
132
|
+
: "";
|
|
133
|
+
|
|
134
|
+
const symbolSettings = libConfig.includeSymbols
|
|
135
|
+
? `
|
|
136
|
+
<DebugType>embedded</DebugType>
|
|
137
|
+
<DebugSymbols>true</DebugSymbols>`
|
|
138
|
+
: `
|
|
139
|
+
<DebugType>none</DebugType>`;
|
|
140
|
+
|
|
141
|
+
const packageSettings =
|
|
142
|
+
libConfig.packable && libConfig.packageMetadata
|
|
143
|
+
? generatePackageMetadata(libConfig.packageMetadata)
|
|
144
|
+
: "";
|
|
145
|
+
|
|
146
|
+
return ` <PropertyGroup>
|
|
147
|
+
<OutputType>Library</OutputType>
|
|
148
|
+
${targetProp}
|
|
149
|
+
<RootNamespace>${config.rootNamespace}</RootNamespace>
|
|
150
|
+
<AssemblyName>${config.outputName}</AssemblyName>
|
|
151
|
+
<Nullable>enable</Nullable>
|
|
152
|
+
<ImplicitUsings>false</ImplicitUsings>${docSettings}${symbolSettings}
|
|
153
|
+
<IsPackable>${libConfig.packable}</IsPackable>${packageSettings}
|
|
154
|
+
</PropertyGroup>`;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Generate property group for console app output
|
|
159
|
+
*/
|
|
160
|
+
const generateConsoleAppProperties = (
|
|
161
|
+
config: BuildConfig,
|
|
162
|
+
consoleConfig: ConsoleAppConfig
|
|
163
|
+
): string => {
|
|
164
|
+
return ` <PropertyGroup>
|
|
165
|
+
<OutputType>Exe</OutputType>
|
|
166
|
+
<TargetFramework>${consoleConfig.targetFramework}</TargetFramework>
|
|
167
|
+
<RootNamespace>${config.rootNamespace}</RootNamespace>
|
|
168
|
+
<AssemblyName>${config.outputName}</AssemblyName>
|
|
169
|
+
<Nullable>enable</Nullable>
|
|
170
|
+
<ImplicitUsings>false</ImplicitUsings>
|
|
171
|
+
<PublishSingleFile>${consoleConfig.singleFile}</PublishSingleFile>
|
|
172
|
+
<SelfContained>${consoleConfig.selfContained}</SelfContained>
|
|
173
|
+
</PropertyGroup>`;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Generate property group based on output type
|
|
178
|
+
*/
|
|
179
|
+
const generatePropertyGroup = (
|
|
180
|
+
config: BuildConfig,
|
|
181
|
+
outputConfig: OutputConfig
|
|
182
|
+
): string => {
|
|
183
|
+
switch (outputConfig.type) {
|
|
184
|
+
case "executable":
|
|
185
|
+
return generateExecutableProperties(config, outputConfig);
|
|
186
|
+
case "library":
|
|
187
|
+
return generateLibraryProperties(config, outputConfig);
|
|
188
|
+
case "console-app":
|
|
189
|
+
return generateConsoleAppProperties(config, outputConfig);
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Generate complete .csproj file content
|
|
195
|
+
*/
|
|
196
|
+
export const generateCsproj = (config: BuildConfig): string => {
|
|
197
|
+
const packageRefs = formatPackageReferences(config.packages);
|
|
198
|
+
const assemblyRefs = formatAssemblyReferences(
|
|
199
|
+
config.assemblyReferences ?? []
|
|
200
|
+
);
|
|
201
|
+
const runtimeRef = config.runtimePath
|
|
202
|
+
? `
|
|
203
|
+
<ItemGroup>
|
|
204
|
+
<ProjectReference Include="${config.runtimePath}" />
|
|
205
|
+
</ItemGroup>`
|
|
206
|
+
: "";
|
|
207
|
+
|
|
208
|
+
const propertyGroup = generatePropertyGroup(config, config.outputConfig);
|
|
209
|
+
|
|
210
|
+
return `<Project Sdk="Microsoft.NET.Sdk">
|
|
211
|
+
${propertyGroup}${packageRefs}${assemblyRefs}${runtimeRef}
|
|
212
|
+
</Project>
|
|
213
|
+
`;
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Legacy function for backward compatibility
|
|
218
|
+
* @deprecated Use generateCsproj with outputConfig instead
|
|
219
|
+
*/
|
|
220
|
+
export const generateCsprojLegacy = (
|
|
221
|
+
config: BuildConfig & {
|
|
222
|
+
invariantGlobalization?: boolean;
|
|
223
|
+
stripSymbols?: boolean;
|
|
224
|
+
optimizationPreference?: "Size" | "Speed";
|
|
225
|
+
}
|
|
226
|
+
): string => {
|
|
227
|
+
// Convert legacy config to new format
|
|
228
|
+
const execConfig: ExecutableConfig = {
|
|
229
|
+
type: "executable",
|
|
230
|
+
nativeAot: true,
|
|
231
|
+
singleFile: true,
|
|
232
|
+
trimmed: true,
|
|
233
|
+
stripSymbols: config.stripSymbols ?? true,
|
|
234
|
+
optimization: config.optimizationPreference ?? "Speed",
|
|
235
|
+
invariantGlobalization: config.invariantGlobalization ?? true,
|
|
236
|
+
selfContained: true,
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const newConfig: BuildConfig = {
|
|
240
|
+
...config,
|
|
241
|
+
outputConfig: execConfig,
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
return generateCsproj(newConfig);
|
|
245
|
+
};
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for backend build process
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* NuGet package reference
|
|
7
|
+
*/
|
|
8
|
+
export type NuGetPackage = {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly version: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Output type taxonomy
|
|
15
|
+
*/
|
|
16
|
+
export type OutputType = "executable" | "library" | "console-app";
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* NuGet package metadata for libraries
|
|
20
|
+
*/
|
|
21
|
+
export type PackageMetadata = {
|
|
22
|
+
readonly id: string;
|
|
23
|
+
readonly version: string;
|
|
24
|
+
readonly authors: readonly string[];
|
|
25
|
+
readonly description: string;
|
|
26
|
+
readonly projectUrl?: string;
|
|
27
|
+
readonly license?: string;
|
|
28
|
+
readonly tags?: readonly string[];
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Executable-specific configuration
|
|
33
|
+
*/
|
|
34
|
+
export type ExecutableConfig = {
|
|
35
|
+
readonly type: "executable";
|
|
36
|
+
readonly nativeAot: boolean;
|
|
37
|
+
readonly singleFile: boolean;
|
|
38
|
+
readonly trimmed: boolean;
|
|
39
|
+
readonly stripSymbols: boolean;
|
|
40
|
+
readonly optimization: "Size" | "Speed";
|
|
41
|
+
readonly invariantGlobalization: boolean;
|
|
42
|
+
readonly selfContained: boolean;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Library-specific configuration
|
|
47
|
+
*/
|
|
48
|
+
export type LibraryConfig = {
|
|
49
|
+
readonly type: "library";
|
|
50
|
+
readonly targetFrameworks: readonly string[];
|
|
51
|
+
readonly generateDocumentation: boolean;
|
|
52
|
+
readonly includeSymbols: boolean;
|
|
53
|
+
readonly packable: boolean;
|
|
54
|
+
readonly packageMetadata?: PackageMetadata;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Console app configuration (non-NativeAOT)
|
|
59
|
+
*/
|
|
60
|
+
export type ConsoleAppConfig = {
|
|
61
|
+
readonly type: "console-app";
|
|
62
|
+
readonly selfContained: boolean;
|
|
63
|
+
readonly singleFile: boolean;
|
|
64
|
+
readonly targetFramework: string;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Output configuration union type
|
|
69
|
+
*/
|
|
70
|
+
export type OutputConfig = ExecutableConfig | LibraryConfig | ConsoleAppConfig;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Assembly reference (for DLL files)
|
|
74
|
+
*/
|
|
75
|
+
export type AssemblyReference = {
|
|
76
|
+
readonly name: string;
|
|
77
|
+
readonly hintPath: string;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Build configuration options
|
|
82
|
+
*/
|
|
83
|
+
export type BuildConfig = {
|
|
84
|
+
readonly rootNamespace: string;
|
|
85
|
+
readonly outputName: string;
|
|
86
|
+
readonly dotnetVersion: string;
|
|
87
|
+
readonly runtimePath?: string;
|
|
88
|
+
readonly assemblyReferences?: readonly AssemblyReference[];
|
|
89
|
+
readonly packages: readonly NuGetPackage[];
|
|
90
|
+
readonly outputConfig: OutputConfig;
|
|
91
|
+
// Legacy fields for backward compatibility
|
|
92
|
+
readonly invariantGlobalization?: boolean;
|
|
93
|
+
readonly stripSymbols?: boolean;
|
|
94
|
+
readonly optimizationPreference?: "Size" | "Speed";
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Entry point information
|
|
99
|
+
*/
|
|
100
|
+
export type EntryInfo = {
|
|
101
|
+
readonly namespace: string;
|
|
102
|
+
readonly className: string;
|
|
103
|
+
readonly methodName: string;
|
|
104
|
+
readonly isAsync: boolean;
|
|
105
|
+
readonly needsProgram: boolean;
|
|
106
|
+
readonly runtime?: "js" | "dotnet";
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Build options passed to buildNativeAot
|
|
111
|
+
*/
|
|
112
|
+
export type BuildOptions = {
|
|
113
|
+
readonly namespace: string;
|
|
114
|
+
readonly outputName?: string;
|
|
115
|
+
readonly dotnetVersion?: string;
|
|
116
|
+
readonly rid?: string;
|
|
117
|
+
readonly keepTemp?: boolean;
|
|
118
|
+
readonly stripSymbols?: boolean;
|
|
119
|
+
readonly optimizationPreference?: "Size" | "Speed";
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Result of the build process
|
|
124
|
+
*/
|
|
125
|
+
export type BuildResult =
|
|
126
|
+
| {
|
|
127
|
+
readonly ok: true;
|
|
128
|
+
readonly outputPath: string;
|
|
129
|
+
readonly buildDir: string;
|
|
130
|
+
}
|
|
131
|
+
| {
|
|
132
|
+
readonly ok: false;
|
|
133
|
+
readonly error: string;
|
|
134
|
+
readonly buildDir?: string;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Dotnet execution result
|
|
139
|
+
*/
|
|
140
|
+
export type DotnetResult =
|
|
141
|
+
| {
|
|
142
|
+
readonly ok: true;
|
|
143
|
+
readonly stdout: string;
|
|
144
|
+
}
|
|
145
|
+
| {
|
|
146
|
+
readonly ok: false;
|
|
147
|
+
readonly error: string;
|
|
148
|
+
readonly stdout?: string;
|
|
149
|
+
readonly stderr?: string;
|
|
150
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"outDir": "./dist",
|
|
5
|
+
"rootDir": "./src",
|
|
6
|
+
"composite": true,
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"declarationMap": true,
|
|
9
|
+
"tsBuildInfoFile": "./dist/.tsbuildinfo"
|
|
10
|
+
},
|
|
11
|
+
"include": ["src/**/*.ts"],
|
|
12
|
+
"exclude": ["node_modules", "dist"],
|
|
13
|
+
"references": [{ "path": "../frontend" }, { "path": "../emitter" }]
|
|
14
|
+
}
|