#include "doc_json.h" #include "libs/jansson.h" namespace scripting { static void json_doc_generate_class(json_t* elObj, const DocumentationElementClass* lib) { json_object_set_new(elObj, "superClass", json_string(lib->superClass.c_str())); } static json_t* json_doc_generate_return_type(const scripting::ade_type_info& type_info) { switch (type_info.getType()) { case ade_type_info_type::Empty: return json_string("void"); case ade_type_info_type::Simple: return json_string(type_info.getIdentifier()); case ade_type_info_type::Tuple: { json_t* tupleTypes = json_array(); for (const auto& type : type_info.elements()) { json_array_append_new(tupleTypes, json_doc_generate_return_type(type)); } return json_pack("{ssso}", "type", "tuple", "elements", tupleTypes); } case ade_type_info_type::Array: { return json_pack("{ssso}", "type", "list", "element", json_doc_generate_return_type(type_info.elements().front())); } case ade_type_info_type::Map: { return json_pack("{sssoso}", "type", "map", "key", json_doc_generate_return_type(type_info.elements()[0]), "value", json_doc_generate_return_type(type_info.elements()[1])); } case ade_type_info_type::Iterator: { return json_pack("{ssso}", "type", "iterator", "element", json_doc_generate_return_type(type_info.elements().front())); } case ade_type_info_type::Alternative: { json_t* alternativeTypes = json_array(); for (const auto& type : type_info.elements()) { json_array_append_new(alternativeTypes, json_doc_generate_return_type(type)); } return json_pack("{ssso}", "type", "alternative", "elements", alternativeTypes); } case ade_type_info_type::Function: { const auto& elements = type_info.elements(); json_t* parameterTypes = json_array(); if (elements.size() > 1) { for (auto iter = elements.begin() + 1; iter != elements.end(); ++iter) { json_array_append_new(parameterTypes, json_pack("{ssso}", "name", iter->getName().c_str(), "type", json_doc_generate_return_type(*iter))); } } return json_pack("{sssoso}", "type", "function", "returnType", json_doc_generate_return_type(elements.front()), "parameters", parameterTypes); } case ade_type_info_type::Generic: { const auto& elements = type_info.elements(); json_t* parameterTypes = json_array(); if (elements.size() > 1) { for (auto iter = elements.begin() + 1; iter != elements.end(); ++iter) { json_array_append_new(parameterTypes, json_doc_generate_return_type(*iter)); } } return json_pack("{sssoso}", "type", "generic", "baseType", json_doc_generate_return_type(elements.front()), "parameters", parameterTypes); } case ade_type_info_type::Varargs: { return json_pack("{ssso}", "type", "varargs", "baseType", json_doc_generate_return_type(type_info.elements().front())); } } UNREACHABLE("Unknown type type %d!", static_cast(type_info.getType())); return nullptr; } static json_t* json_doc_function_signature(const SCP_vector& args) { json_t* arr = json_array(); for (const auto& arg : args) { json_array_append_new(arr, json_pack("{sosssssbss}", "type", json_doc_generate_return_type(arg.type), "name", arg.name.c_str(), "default", arg.def_val.c_str(), "optional", arg.optional, "description", arg.comment.c_str())); } return arr; } static void json_doc_generate_function(json_t* elObj, const DocumentationElementFunction* lib) { json_object_set_new(elObj, "returnType", json_doc_generate_return_type(lib->returnType)); json_object_set_new(elObj, "returnDocumentation", json_string(lib->returnDocumentation.c_str())); if (lib->overloads.size() == 1 && !lib->overloads.front().simple.empty()) { // Legacy argument list not filled with argument data json_object_set_new(elObj, "parameters", json_string(lib->overloads.front().simple.c_str())); } else { json_t* arr = json_array(); for (const auto& overload : lib->overloads) { if (!overload.simple.empty()) { json_array_append_new(arr, json_string(overload.simple.c_str())); } else { json_array_append_new(arr, json_doc_function_signature(overload.arguments)); } } json_object_set_new(elObj, "parameters", arr); } } static void json_doc_generate_property(json_t* elObj, const DocumentationElementProperty* lib) { json_object_set_new(elObj, "getterType", json_doc_generate_return_type(lib->getterType)); json_object_set_new(elObj, "setterType", json_doc_generate_return_type(lib->setterType)); json_object_set_new(elObj, "returnDocumentation", json_string(lib->returnDocumentation.c_str())); } static json_t* json_doc_generate_elements(const SCP_vector>& elements); static json_t* json_doc_generate_element(const std::unique_ptr& element) { json_t* elementsObj = json_object(); json_object_set_new(elementsObj, "name", json_string(element->name.c_str())); json_object_set_new(elementsObj, "shortName", json_string(element->shortName.c_str())); json_object_set_new(elementsObj, "description", json_string(element->description.c_str())); switch (element->type) { case ElementType::Library: json_object_set_new(elementsObj, "type", json_string("library")); break; case ElementType::Class: json_object_set_new(elementsObj, "type", json_string("class")); json_doc_generate_class(elementsObj, static_cast(element.get())); break; case ElementType::Function: json_object_set_new(elementsObj, "type", json_string("function")); json_doc_generate_function(elementsObj, static_cast(element.get())); break; case ElementType::Operator: json_object_set_new(elementsObj, "type", json_string("operator")); json_doc_generate_function(elementsObj, static_cast(element.get())); break; case ElementType::Property: json_object_set_new(elementsObj, "type", json_string("property")); json_doc_generate_property(elementsObj, static_cast(element.get())); break; default: json_object_set_new(elementsObj, "type", json_string("unknown")); break; } json_object_set_new(elementsObj, "children", json_doc_generate_elements(element->children)); return elementsObj; } static json_t* json_doc_generate_elements(const SCP_vector>& elements) { json_t* elementsArray = json_array(); for (const auto& el : elements) { json_array_append_new(elementsArray, json_doc_generate_element(el)); } return elementsArray; } static json_t* json_doc_generate_param_element(const HookVariableDocumentation& param) { return json_pack("{s:s,s:s,s:o}", "name", param.name, "description", param.description, "type", json_doc_generate_return_type(param.type)); } static json_t* json_doc_generate_action_element(const DocumentationAction& action) { json_t* paramArray = json_array(); json_t* conditionArray = json_array(); for (const auto& param : action.parameters) { json_array_append_new(paramArray, json_doc_generate_param_element(param)); } for (const auto& condition : action.conditions) { json_array_append_new(conditionArray, json_pack("{s:s,s:s}", "name", condition.first.c_str(), "description", condition.second->documentation.c_str())); } return json_pack("{s:s,s:s,s:o,s:o,s:b}", "name", action.name.c_str(), "description", action.description.c_str(), "hookVars", paramArray, "conditions", conditionArray, "overridable", action.overridable); } void output_json_doc(const ScriptingDocumentation& doc, const SCP_string& filename) { std::unique_ptr root(json_object()); // Should be incremented every time an incompatible change is made json_object_set_new(root.get(), "version", json_integer(2)); { json_t* actionArray = json_array(); for (const auto& action : doc.actions) { json_array_append_new(actionArray, json_doc_generate_action_element(action)); } json_object_set_new(root.get(), "actions", actionArray); } { json_t* conditionArray = json_array(); for (const auto& cond : doc.conditions) { json_array_append_new(conditionArray, json_string(cond.c_str())); } json_object_set_new(root.get(), "conditions", conditionArray); } { json_t* optionsArray = json_array(); for (const auto& option : doc.options) { json_t* optionsObject = json_object(); json_object_set_new(optionsObject, "title", json_string(option.title.c_str())); json_object_set_new(optionsObject, "key", json_string(option.key.c_str())); json_object_set_new(optionsObject, "description", json_string(option.description.c_str())); json_array_append_new(optionsArray, optionsObject); } json_object_set_new(root.get(), "options", optionsArray); } { json_t* enumObject = json_object(); for (const auto& enumVal : doc.enumerations) { json_object_set_new(enumObject, enumVal.name.c_str(), json_integer(enumVal.value)); } json_object_set_new(root.get(), "enums", enumObject); } { json_t* globalVariables = json_array(); for (const auto& param : doc.globalVariables) { json_array_append_new(globalVariables, json_doc_generate_param_element(param)); } json_object_set_new(root.get(), "globalVars", globalVariables); } json_object_set_new(root.get(), "elements", json_doc_generate_elements(doc.elements)); const auto jsonStr = json_dump_string(root.get(), JSON_INDENT(2) | JSON_SORT_KEYS); std::ofstream outStr(filename, std::ios::binary); outStr << jsonStr; } } // namespace scripting