cpp-merge
Version:
Command line tool to produce single source file from multiple C/C++ files
183 lines • 8.5 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs_1 = __importDefault(require("fs"));
const CppFileMerger_1 = __importDefault(require("../parse/CppFileMerger"));
const errors_1 = require("../parse/errors");
const ArgumentParser_1 = __importStar(require("./ArgumentParser"));
const CliError_1 = __importStar(require("./CliError"));
var ArgumentName;
(function (ArgumentName) {
ArgumentName["File"] = "file";
})(ArgumentName || (ArgumentName = {}));
var OptionName;
(function (OptionName) {
OptionName["Help"] = "help";
OptionName["Include"] = "include";
OptionName["Source"] = "source";
OptionName["Output"] = "output";
})(OptionName || (OptionName = {}));
class Cli {
constructor(output = process.stdout) {
this.output = output;
this.argumentParser = new ArgumentParser_1.default({
programName: "cpp-merge",
description: "A tool to produce single file from multiple C/C++ files. By default the produced content is " +
"displayed on the standard output. To store it in a file use option -o or --output."
});
this.argumentParser.addArgument({
name: ArgumentName.File,
description: "Input file which will be processed. In most cases it will be file with main function.",
valueName: "file"
});
this.argumentParser.addOption({
name: OptionName.Help,
options: ["--help"],
description: "Show this help text."
});
this.argumentParser.addOption({
name: OptionName.Include,
options: ["-i", "--include"],
description: "Path to additional directory where header files are located. Program will search for include " +
"files first in directory where currently processed file is located and then in this directory.",
value: { name: "path" }
});
this.argumentParser.addOption({
name: OptionName.Source,
options: ["-s", "--source"],
description: "Path to additional directory where source files are located. After processing all included files, " +
"program will try to find related source file for each of included local header files. If file with same " +
"base name and extension .c or .cpp exists, it will be appended to the output. Program will search first " +
"in the same directory where main source file is located and then in additional source directory.",
value: { name: "path" }
});
this.argumentParser.addOption({
name: OptionName.Output,
options: ["-o", "--output"],
description: "Store output in a file, instead of displaying it on the standard output.",
value: { name: "file" }
});
}
run(args) {
if (args.length === 0) {
this.printHelp();
return;
}
try {
const { help, inputFilePath, includeDirectory, sourceDirectory, outputFilePath } = this.parseArguments(args);
if (help) {
this.printHelp();
return;
}
const content = this.parseFile(inputFilePath, includeDirectory, sourceDirectory);
if (outputFilePath) {
this.writeToFile(outputFilePath, content);
}
else {
this.output.write(content);
}
}
catch (error) {
if (error instanceof errors_1.ParseError) {
throw new CliError_1.default(`Error parsing file '${error.file}': ${error.message}`, CliError_1.ErrorCode.ParseError);
}
if (error instanceof ArgumentParser_1.UnknownOptionError) {
throw new CliError_1.default(`Unknown option: '${error.argument}'`, CliError_1.ErrorCode.ArgumentError);
}
if (error instanceof ArgumentParser_1.UnknownArgumentError) {
throw new CliError_1.default(`Unknown argument: '${error.argument}'`, CliError_1.ErrorCode.ArgumentError);
}
if (error instanceof ArgumentParser_1.ArgumentError) {
throw new CliError_1.default(`Invalid argument '${error.argument}': ${error.message}`, CliError_1.ErrorCode.ArgumentError);
}
throw error;
}
}
printHelp() {
this.output.write(this.argumentParser.formatHelp());
}
parseArguments(args) {
const result = this.argumentParser.parseArguments(args);
return {
help: result.options[OptionName.Help] != null,
inputFilePath: result.arguments[ArgumentName.File],
includeDirectory: result.options[OptionName.Include],
sourceDirectory: result.options[OptionName.Source],
outputFilePath: result.options[OptionName.Output]
};
}
parseFile(inputFilePath, includeDirectory, sourceDirectory) {
if (!inputFilePath) {
throw new CliError_1.default('Missing input file', CliError_1.ErrorCode.ArgumentError);
}
this.validateInputFile(inputFilePath);
if (includeDirectory) {
this.validateIncludeDirectory(includeDirectory);
}
if (sourceDirectory) {
this.validateSourceDirectory(sourceDirectory);
}
const fileMerger = new CppFileMerger_1.default({ includeDirectory, sourceDirectory });
return fileMerger.parse(inputFilePath);
}
validateInputFile(inputFilePath) {
if (!fs_1.default.existsSync(inputFilePath)) {
throw new CliError_1.default(`Input file '${inputFilePath}' doesn't exist`, CliError_1.ErrorCode.ArgumentError);
}
if (!fs_1.default.statSync(inputFilePath).isFile()) {
throw new CliError_1.default(`${inputFilePath} is not a file`, CliError_1.ErrorCode.ArgumentError);
}
}
validateIncludeDirectory(includeDirectory) {
if (!fs_1.default.existsSync(includeDirectory)) {
throw new CliError_1.default(`Include directory '${includeDirectory}' doesn't exist`, CliError_1.ErrorCode.ArgumentError);
}
if (!fs_1.default.statSync(includeDirectory).isDirectory()) {
throw new CliError_1.default(`${includeDirectory} is not a directory`, CliError_1.ErrorCode.ArgumentError);
}
}
validateSourceDirectory(sourceDirectory) {
if (!fs_1.default.existsSync(sourceDirectory)) {
throw new CliError_1.default(`Source directory '${sourceDirectory}' doesn't exist`, CliError_1.ErrorCode.ArgumentError);
}
if (!fs_1.default.statSync(sourceDirectory).isDirectory()) {
throw new CliError_1.default(`${sourceDirectory} is not a directory`, CliError_1.ErrorCode.ArgumentError);
}
}
writeToFile(outputFilePath, content) {
try {
fs_1.default.writeFileSync(outputFilePath, content);
}
catch (error) {
const causeMessage = error instanceof Error ? error.message : 'Unknown error';
throw new CliError_1.default(`Error writing output to file '${outputFilePath}': ${causeMessage}`, CliError_1.ErrorCode.WriteError);
}
}
}
exports.default = Cli;
//# sourceMappingURL=Cli.js.map