Skip to content

Instantly share code, notes, and snippets.

@snowyyd
Last active February 16, 2025 17:57
Show Gist options
  • Save snowyyd/0ab93efe562f0af32a7e5ec5c5463a1d to your computer and use it in GitHub Desktop.
Save snowyyd/0ab93efe562f0af32a7e5ec5c5463a1d to your computer and use it in GitHub Desktop.
Merge C# files into a single one
/**
* Usage: node --experimental-strip-types merge.ts
*/
"use strict";
import fs from 'node:fs/promises';
import path from 'node:path';
const usingRe = /^using ([A-Za-z0-9.= ]+);?/;
const sanitizeMultilineStr = (str: string) => str.replace(/\t+/gm, '').replace(/\{tab\}/g, '\t');
async function writeFile(dir: string, filename: string, data: string)
{
await fs.mkdir(dir, { recursive: true });
return fs.writeFile(path.join(dir, filename), data, 'utf8');
}
async function readFiles(dir: string)
{
const parsedContent: string[] = [];
const usingLibs = new Set();
const files = (await fs.readdir(dir, { withFileTypes: true, recursive: true }))
.filter((x) => x.isFile() && x.name.endsWith('.cs')) // filter .cs files only
.map((x) => path.join(x.parentPath, x.name)); // return an array of paths
const contents = await Promise.all(files.map((file) => fs.readFile(file, 'utf8')));
contents.forEach((content, idx) =>
{
const filteredContent = content
.split('\n') // split lines
.filter((line) =>
{
const usingsFound = line.trim().match(usingRe);
if (usingsFound)
{
usingLibs.add(usingsFound[1]);
return false; // exclude the line with the "using directive"
}
return true;
})
.join('\n'); // join all "lines" again
const contentWithNewLines = content.endsWith('\n') ? `${filteredContent.trim()}\n` : `${filteredContent.trim()}\n\n`;
parsedContent.push(`// Content of: ${files.at(idx)}\n${contentWithNewLines}`);
});
return {
using: usingLibs,
contents: parsedContent,
};
};
(async () =>
{
const args = process.argv.splice(2);
const srcPath = args[0];
const className = args[1];
if (args.length === 0)
{
console.log('Parameters: <source path> <class name>');
process.exit(1);
}
if (!srcPath) throw new Error('You must set a source path!');
if (!className) throw new Error('You must set the main class name!');
const res = await readFiles(srcPath);
let output = sanitizeMultilineStr(`
// This file was autogenerated using the merge tool
// ${new Date().toString()}
{usings}
{contents}
`);
output = output
.replace('{usings}', Array.from(res.using).map((x) => `using ${x};`).join('\n'))
.replace('{contents}', res.contents.join('\n'));
await writeFile('dist', `${className}.cs`, output);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment