Skip to content

fix: validate the user inputs and add documentation for the CLI #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ cmake-build-*/
$RECYCLE.BIN/
.TemporaryItems
ehthumbs.db
Thumbs.db
Thumbs.db

.cache/
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,28 @@ Features


See the [test](test) folder for examples for building resources, using the valijson adapter, constexpr usage of resources, and firewalled usage of resources.

## CLI Usage

The json2cpp CLI can be used to convert a JSON file into a C++ source file that can be compiled into your project.

```shell
json2cpp version 0.0.1
Usage: ./build/src/Debug/json2cpp [OPTIONS] [<document_name>] [<input_file_name>] [<output_base_name>]

Positionals:
<document_name> TEXT The name of the document used in the generated C++ namespace and include guards
<input_file_name> TEXT The input JSON file to compile
<output_base_name> TEXT The base path for the output files. It will generate <output_base_name>.cpp and <output_base_name>.hpp

Options:
-h,--help Print this help message and exit
--version Show version information

```

For example, to compile a JSON file named `"./data/data.json"`:

```shell
json2cpp "data" "./data.json" "./data_source"
```
34 changes: 34 additions & 0 deletions src/json2cpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ SOFTWARE.


#include "json2cpp.hpp"
#include <algorithm>
#include <cctype>
#include <fmt/std.h>
#include <fstream>

std::string compile(const nlohmann::json &value, std::size_t &obj_count, std::vector<std::string> &lines)
Expand Down Expand Up @@ -85,8 +88,35 @@ std::string compile(const nlohmann::json &value, std::size_t &obj_count, std::ve
return "unhandled";
}


/**
* @brief Checks if the given string is a valid C++ identifier. A valid C++ identifier is a string that starts with an
* alphabetic character and is followed by zero or more alphanumeric characters.
*
* @param name The string to check
* @return true if the string is a valid C++ identifier, false otherwise
*/
bool is_valid_identifier(const std::string_view name)
{
// not empty
return !name.empty()
// starts with an alphabetic character
&& std::isalpha(name.front()) != 0
// and is followed by zero or more alphanumeric characters
&& std::all_of(name.begin(), name.end(), [](const auto &chr) { return std::isalnum(chr) != 0; });
}

void assert_valid_identifier(const std::string_view document_name)
{
if (!is_valid_identifier(document_name)) {
throw std::invalid_argument(
fmt::format("document_name '{}' must be a non-empty valid C++ identifier", document_name));
}
}

compile_results compile(const std::string_view document_name, const nlohmann::json &json)
{
assert_valid_identifier(document_name);

std::size_t obj_count{ 0 };

Expand Down Expand Up @@ -150,6 +180,7 @@ compile_results compile(const std::string_view document_name, const std::filesys
spdlog::info("Loading file: '{}'", filename.string());

std::ifstream input(filename);
if (!input.is_open()) { throw std::runtime_error(fmt::format("Unable to open the input file name: {}", filename)); }
nlohmann::json document;
input >> document;

Expand All @@ -162,9 +193,12 @@ void write_compilation([[maybe_unused]] std::string_view document_name,
const compile_results &results,
const std::filesystem::path &base_output)
{
assert_valid_identifier(document_name);

const auto append_extension = [](std::filesystem::path name, std::string_view ext) { return name += ext; };

// Create the directory of the base_output's parent
std::filesystem::create_directories(base_output.parent_path());

const auto hpp_name = append_extension(base_output, ".hpp");
const auto cpp_name = append_extension(base_output, ".cpp");
Expand Down
17 changes: 10 additions & 7 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ SOFTWARE.
*/

#include <filesystem>
#include <fstream>
#include <functional>
#include <iostream>
#include <string>

#include "json2cpp.hpp"
#include <CLI/CLI.hpp>
Expand All @@ -39,13 +37,18 @@ int main(int argc, const char **argv)

std::string document_name;
std::filesystem::path input_file_name;
std::filesystem::path output_base_name;
std::filesystem::path output_base_name = "out";

bool show_version = false;
app.add_flag("--version", show_version, "Show version information");
app.add_option("<document_name>", document_name);
app.add_option("<input_file_name>", input_file_name);
app.add_option("<output_base_name>", output_base_name);
app.add_option("<document_name>",
document_name,
"The name of the document used in the generated C++ namespace and include guards");
app.add_option("<input_file_name>", input_file_name, "The input JSON file to compile");
app.add_option("<output_base_name>",
output_base_name,
"The base path for the output filesThe base path for the output files. It will generate <output_base_name>.cpp "
"and <output_base_name>.hpp");
CLI11_PARSE(app, argc, argv);

compile_to(document_name, input_file_name, output_base_name);
Expand Down