in src/TypeSpec.Extension/Emitter.Csharp/src/emitter.ts [24:210]
export async function $onEmit(context: EmitContext<AzureCSharpEmitterOptions>) {
const program: Program = context.program;
if (program.compilerOptions.noEmit || program.hasError()) return;
const options = resolveAzureEmitterOptions(context);
/* set the loglevel. */
const logger = new Logger(program, options.logLevel);
if (
context.emitterOutputDir &&
path.basename(context.emitterOutputDir) === "src"
) {
context.emitterOutputDir = path.dirname(context.emitterOutputDir);
}
logger.info("Starting Microsoft Generator Csharp emitter.");
const sdkContext = await createSdkContext(
context,
"@azure-tools/typespec-csharp",
azureSDKContextOptions
);
const csharpEmitterContext = createCSharpEmitterContext(sdkContext, logger);
const root = createModel(csharpEmitterContext);
const outputFolder = resolvePath(
context.emitterOutputDir ?? "./tsp-output"
);
const isSrcFolder = path.basename(outputFolder) === "src";
const generatedFolder = isSrcFolder
? resolvePath(outputFolder, "Generated")
: resolvePath(outputFolder, "src", "Generated");
if (root) {
if (!fs.existsSync(generatedFolder)) {
fs.mkdirSync(generatedFolder, { recursive: true });
}
// write the tspCodeModel.json file
await writeCodeModel(csharpEmitterContext, root, outputFolder);
//resolve shared folders based on generator path override
const resolvedSharedFolders: string[] = [];
const sharedFolders = [
resolvePath(options.csharpGeneratorPath, "..", "Generator.Shared"),
resolvePath(options.csharpGeneratorPath, "..", "Azure.Core.Shared")
];
for (const sharedFolder of sharedFolders) {
resolvedSharedFolders.push(
path
.relative(generatedFolder, sharedFolder)
.replaceAll("\\", "/")
);
}
const configurations: any = {};
configurations["output-folder"] = ".";
const namespace = options["namespace"] ?? root.name;
configurations["namespace"] = namespace;
configurations["library-name"] = options["library-name"] ?? namespace;
configurations["unreferenced-types-handling"] =
options["unreferenced-types-handling"];
configurations["disable-xml-docs"] =
options["disable-xml-docs"] === false
? undefined
: options["disable-xml-docs"];
configurations["head-as-boolean"] = options["head-as-boolean"];
configurations["deserialize-null-collection-as-null-value"] =
options["deserialize-null-collection-as-null-value"];
configurations["flavor"] =
options["flavor"] ??
(configurations.namespace.toLowerCase().startsWith("azure.")
? "azure"
: undefined);
//only emit these if they are not the default values
configurations["generate-sample-project"] =
options["generate-sample-project"] === true
? undefined
: options["generate-sample-project"];
configurations["generate-test-project"] =
options["generate-test-project"] === false
? undefined
: options["generate-test-project"];
configurations["use-model-reader-writer"] =
options["use-model-reader-writer"];
configurations["use-azure-plugin"] = options["use-azure-plugin"];
configurations["single-top-level-client"] =
options["single-top-level-client"];
configurations["keep-non-overloadable-protocol-signature"] =
options["keep-non-overloadable-protocol-signature"];
configurations["models-to-treat-empty-string-as-null"] =
options["models-to-treat-empty-string-as-null"];
configurations["intrinsic-types-to-treat-empty-string-as-null"] =
options["models-to-treat-empty-string-as-null"]
? options[
"additional-intrinsic-types-to-treat-empty-string-as-null"
].concat(
[
"Uri",
"Guid",
"ResourceIdentifier",
"DateTimeOffset"
].filter(
(item) =>
options[
"additional-intrinsic-types-to-treat-empty-string-as-null"
].indexOf(item) < 0
)
)
: undefined;
configurations["methods-to-keep-client-default-value"] =
options["methods-to-keep-client-default-value"];
configurations["shared-source-folders"] = resolvedSharedFolders ?? [];
configurations["enable-internal-raw-data"] =
options["enable-internal-raw-data"];
configurations["model-namespace"] = options["model-namespace"];
const examplesDir = options["examples-dir"];
if (examplesDir) {
configurations["examples-dir"] = path.relative(
outputFolder,
examplesDir
);
configurations["enable-bicep-serialization"] =
options["enable-bicep-serialization"];
}
/* TODO: when we support to emit decorator list https://github.com/Azure/autorest.csharp/issues/4887, we will update to use emitted decorator to identify if it is azure-arm */
/* set azure-arm */
configurations["azure-arm"] =
sdkContext.arm === false ? undefined : sdkContext.arm;
// Write the config file
await program.host.writeFile(
resolvePath(outputFolder, configurationFileName),
prettierOutput(JSON.stringify(configurations, null, 2))
);
const csProjFile = resolvePath(
isSrcFolder ? outputFolder : resolvePath(outputFolder, "src"),
`${configurations["library-name"]}.csproj`
);
logger.info(`Checking if ${csProjFile} exists`);
const newProjectOption =
options["new-project"] || !existsSync(csProjFile)
? "--new-project"
: "";
const existingProjectOption = options["existing-project-folder"]
? `--existing-project-folder ${options["existing-project-folder"]}`
: "";
const debugFlag = (options.debug ?? false) ? " --debug" : "";
const command = `dotnet --roll-forward Major ${resolvePath(
options.csharpGeneratorPath
)} --project-path ${outputFolder} ${newProjectOption} ${existingProjectOption} --clear-output-folder ${
options["clear-output-folder"]
}${debugFlag}`;
logger.info(command);
try {
execSync(command, { stdio: "inherit" });
} catch (error: any) {
if (error.message) logger.info(error.message);
if (error.stderr) logger.error(error.stderr);
if (error.stdout) logger.verbose(error.stdout);
throw error;
}
if (!options["save-inputs"]) {
// delete
deleteFile(resolvePath(outputFolder, tspOutputFileName), logger);
deleteFile(
resolvePath(outputFolder, configurationFileName),
logger
);
}
}
}