Skip to content
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

Json schema #4369

Merged
merged 23 commits into from
Jul 10, 2017
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
2b79e11
Added empty generator for json schema (idl_gen_json_schema.cpp)
schoetbi Jun 23, 2017
5a4e0f8
JsonSchemaGenerator: output of tables implemented
schoetbi Jun 23, 2017
85edf5b
JsonSchemaGenerator: Corrected generation of typenames
schoetbi Jun 23, 2017
7a73168
JsonSchemaGenerator: Added generation of enum types
schoetbi Jun 23, 2017
352afa9
idl_gen_json_schema.cpp: Write required properties to schema
schoetbi Jun 27, 2017
16e199e
idl_gen_json_schema.cpp: Export Types including namespace
schoetbi Jun 27, 2017
146107f
idl_gen_json_schema.cpp: Fixed Json format
schoetbi Jun 28, 2017
8b6ce58
idl_gen_json_schema.cpp: Formatted according to google code style
schoetbi Jun 28, 2017
323294e
Checked in monster_test.bfbs with changes from master
schoetbi Jun 28, 2017
8ea50de
Added idl_gen_json_schema.cpp in CMakeLists.txt
schoetbi Jun 28, 2017
453e730
generate_code.bat: Added generation of json schema
schoetbi Jun 28, 2017
7d868a8
Added todo.md
schoetbi Jun 28, 2017
05aee5e
generate_code.sh: Added generation of json schema
schoetbi Jun 28, 2017
00100e3
Addressed some review issues
schoetbi Jul 3, 2017
c1ded2e
removed auto in idl_gen_json_schema.cpp
schoetbi Jul 3, 2017
915e277
idl_gen_json_schema.cpp: changed iterator declarations to auto
schoetbi Jul 4, 2017
61bc633
deleted todo.md
schoetbi Jul 4, 2017
4f3a461
idl_gen_json_schema.cpp: Removed keyword "override" so that vs2010 ca…
schoetbi Jul 6, 2017
1ac0859
idl_gen_json_schema.cpp: switch statement in GenType handeles all enu…
schoetbi Jul 7, 2017
4e600de
idl_gen_json_schema.cpp: Removed cerr output
schoetbi Jul 10, 2017
4875f3b
idl_gen_json_schema.cpp: Avoid vector copying
schoetbi Jul 10, 2017
90e976e
idl_gen_json_schema.cpp: Fixed identation of json schema output
schoetbi Jul 10, 2017
2d2fb87
idl_gen_json_schema.cpp: Do not output empty descriptions
schoetbi Jul 10, 2017
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
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ set(FlatBuffers_Compiler_SRCS
src/idl_gen_python.cpp
src/idl_gen_fbs.cpp
src/idl_gen_grpc.cpp
src/idl_gen_json_schema.cpp
src/flatc.cpp
src/flatc_main.cpp
grpc/src/compiler/schema_interface.h
Expand Down
7 changes: 7 additions & 0 deletions include/flatbuffers/idl.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ struct IDLOptions {
kJson = 1 << 7,
kBinary = 1 << 8,
kTs = 1 << 9,
kJsonSchema = 1 << 10,
kMAX
};

Expand Down Expand Up @@ -713,6 +714,12 @@ extern bool GeneratePython(const Parser &parser,
const std::string &path,
const std::string &file_name);

// Generate Json schema file
// See idl_gen_json_schema.cpp.
extern bool GenerateJsonSchema(const Parser &parser,
const std::string &path,
const std::string &file_name);

// Generate C# files from the definitions in the Parser object.
// See idl_gen_csharp.cpp.
extern bool GenerateCSharp(const Parser &parser,
Expand Down
7 changes: 6 additions & 1 deletion src/flatc_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,12 @@ int main(int argc, const char *argv[]) {
flatbuffers::IDLOptions::kPhp,
"Generate PHP files for tables/structs",
flatbuffers::GeneralMakeRule },
};
{ flatbuffers::GenerateJsonSchema, "-S", "--jsonschema", "JsonSchema", true,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets leave out the -S ?

nullptr,
flatbuffers::IDLOptions::kJsonSchema,
"Generate Json schema",
flatbuffers::GeneralMakeRule },
};

flatbuffers::FlatCompiler::InitParams params;
params.generators = generators;
Expand Down
224 changes: 224 additions & 0 deletions src/idl_gen_json_schema.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "flatbuffers/code_generators.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"

namespace flatbuffers {

static std::string GeneratedFileName(const std::string &path,
const std::string &file_name) {
return path + file_name + ".schema.json";
}

namespace jsons {

std::string GenNativeType(BaseType type) {
switch (type) {
case BASE_TYPE_BOOL:
return "boolean";

case BASE_TYPE_CHAR:
case BASE_TYPE_UCHAR:
case BASE_TYPE_SHORT:
case BASE_TYPE_USHORT:
case BASE_TYPE_INT:
case BASE_TYPE_UINT:
case BASE_TYPE_LONG:
case BASE_TYPE_ULONG:
case BASE_TYPE_FLOAT:
case BASE_TYPE_DOUBLE:
return "number";
case BASE_TYPE_STRING:
return "string";
default: { return "?"; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is ? a correct way to do this, or are we missing types?

}
}

template <class T>
std::string GenFullName(const T *enum_def) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to follow the style of the rest of the code-base, thus template on same line.

std::stringstream fullName;
auto nameSpaces = enum_def->defined_namespace->components;
for (auto const &ns : nameSpaces) {
fullName << ns << "_";
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for blank line, here and elsewhere

fullName << enum_def->name;
return fullName.str();
}

template <class T>
std::string GenTypeRef(const T *enum_def) {
return "\"$ref\" : \"#/definitions/" + GenFullName(enum_def) + "\"";
}

std::string GenType(const std::string &name) {
return "\"type\" : \"" + name + "\"";
}

std::string GenType(const Type &type) {
switch (type.base_type) {
case BASE_TYPE_VECTOR: {
std::stringstream typeline;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not that I mind too much, but doesn't seem using stringstream has any advantages here over using stting

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought it would but you are right it gives no benefits. See here: http://quick-bench.com/Xh4YAery7pHuO_AIg_ElnqTc3RU

I will remove them

typeline << "\"type\" : \"array\", ";
if (type.element == BASE_TYPE_STRUCT) {
typeline << "\"items\" : { " << GenTypeRef(type.struct_def) << " }";
} else {
typeline << "\"items\" : { " << GenType(GenNativeType(type.element))
<< " }";
}

return typeline.str();
}
case BASE_TYPE_STRUCT: {
return GenTypeRef(type.struct_def);
}
case BASE_TYPE_UNION: {
std::stringstream unionTypes;
unionTypes << "\"anyOf\": [";
for (auto const &ut : type.enum_def->vals.vec) {
if (ut->union_type.base_type == BASE_TYPE_NONE) {
continue;
}
if (ut->union_type.base_type == BASE_TYPE_STRUCT) {
unionTypes << "{ " + GenTypeRef(ut->union_type.struct_def) + " }";
}

if (&ut != &type.enum_def->vals.vec.back()) {
unionTypes << ",";
}
}
unionTypes << "]";
return unionTypes.str();
}
case BASE_TYPE_UTYPE:
return GenTypeRef(type.enum_def);
}

if (type.base_type == BASE_TYPE_CHAR && type.enum_def != nullptr) {
// it is a reference to an enum type
return GenTypeRef(type.enum_def);
}

return GenType(GenNativeType(type.base_type));
}

class JsonSchemaGenerator : public BaseGenerator {
private:
CodeWriter code_;

public:
JsonSchemaGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
: BaseGenerator(parser, path, file_name, "", "") {}

explicit JsonSchemaGenerator(const BaseGenerator &base_generator)
: BaseGenerator(base_generator) {}

bool generate() override {
code_.Clear();
code_ += "{";
code_ += "\"$schema\": \"http://json-schema.org/draft-04/schema#\",";
code_ += "\"definitions\": {";

for (auto &e : parser_.enums_.vec) {
code_ += "";
code_ += "\"" + GenFullName(e) + "\" : {";
code_ += GenType("string") + ",";
std::stringstream enumdef;
enumdef << "\"enum\": [";
for (auto &enumval : e->vals.vec) {
enumdef << "\"" + enumval->name + "\"";
if (&enumval != &e->vals.vec.back()) {
enumdef << ", ";
}
}
enumdef << "]";
code_ += enumdef.str();
code_ += "},"; // close type
}

for (auto &s : parser_.structs_.vec) {
code_ += "";
code_ += "\"" + GenFullName(s) + "\" : {";
code_ += GenType("object") + ",";
std::stringstream comment;
for (auto commentLine : s->doc_comment) {
comment << commentLine;
}
code_ += "\"description\" : \"" + comment.str() + "\",";
code_ += "\"properties\" : {";

for (auto const &prop : s->fields.vec) {
std::stringstream typeLine;
typeLine << " \"" + prop->name + "\" : { " +
GenType(prop->value.type) + " }";

if (&prop != &s->fields.vec.back()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this if-else can be simplified :)

code_ += typeLine.str() + ",";
} else {
code_ += typeLine.str();
}
}

auto props = s->fields.vec;
std::vector<flatbuffers::FieldDef *> requiredProperties;
std::copy_if(props.begin(), props.end(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ooh fancy :)

std::back_inserter(requiredProperties),
[](flatbuffers::FieldDef *prop) { return prop->required; });
if (requiredProperties.size() > 0) {
code_ += " },"; // close properties
std::stringstream requiredString;
requiredString << "\"required\" : [ ";
for (const auto &reqProp : requiredProperties) {
requiredString << "\"" << reqProp->name << "\"";
if (&reqProp != &requiredProperties.back()) {
requiredString << ", ";
}
}
requiredString << "]";
code_ += requiredString.str();
} else {
code_ += " }"; // close properties
}

if (&s != &parser_.structs_.vec.back()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

simplify

code_ += "},"; // close type
} else {
code_ += "}"; // close type
}
}
code_ += "},"; // close definitions

// mark root type
code_ += "\"$ref\" : \"#/definitions/" +
GenFullName(parser_.root_struct_def_) + "\"";

code_ += "}"; // close schema root
const auto file_path = GeneratedFileName(path_, file_name_);
const auto final_code = code_.ToString();
return SaveFile(file_path.c_str(), final_code, false);
}
};
} // namespace jsons

bool GenerateJsonSchema(const Parser &parser, const std::string &path,
const std::string &file_name) {
jsons::JsonSchemaGenerator generator(parser, path, file_name);
return generator.generate();
}
} // namespace flatbuffers
1 change: 1 addition & 0 deletions tests/generate_code.bat
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ if "%1"=="-b" set buildtype=%2
..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes -I include_test monster_test.fbs monsterdata_test.json
..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test\namespace_test1.fbs namespace_test\namespace_test2.fbs
..\%buildtype%\flatc.exe --binary --schema -I include_test monster_test.fbs
..\%buildtype%\flatc.exe --jsonschema --schema -I include_test monster_test.fbs
1 change: 1 addition & 0 deletions tests/generate_code.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
../flatc --cpp --java --csharp --go --binary --python --js --ts --php --gen-mutable --no-fb-import -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
../flatc --cpp --gen-mutable --gen-object-api -o union_vector ./union_vector/union_vector.fbs
../flatc -b --schema --bfbs-comments -I include_test monster_test.fbs
../flatc --jsonschema --schema -I include_test monster_test.fbs
cd ../samples
../flatc --cpp --gen-mutable --gen-object-api monster.fbs
cd ../reflection
Binary file modified tests/monster_test.bfbs
Binary file not shown.
Loading