Merge branch 'feature/documentation-cleanup'

This commit is contained in:
Ylva Selling
2023-04-26 17:37:50 -04:00
21 changed files with 245 additions and 868 deletions

View File

@@ -25,8 +25,6 @@
#ifndef __OPENSPACE_CORE___DOCUMENTATIONENGINE___H__
#define __OPENSPACE_CORE___DOCUMENTATIONENGINE___H__
#include <openspace/documentation/documentationgenerator.h>
#include <openspace/documentation/documentation.h>
#include <openspace/json.h>
#include <ghoul/misc/exception.h>
@@ -38,7 +36,7 @@ namespace openspace::documentation {
* produced in the application an write them out as a documentation file for human
* consumption.
*/
class DocumentationEngine : public DocumentationGenerator {
class DocumentationEngine {
public:
/**
* This exception is thrown by the addDocumentation method if a provided Documentation
@@ -71,14 +69,6 @@ public:
*/
void addDocumentation(Documentation documentation);
/* Adds the \p templates to the list of templates that are written to the
* documentation html file.
* \param templates Vector of templates to add. Most of the time this list
* will just contain one item, but some modules may wish to provide
* multiple templates for subtypes, etc
*/
void addHandlebarTemplates(std::vector<HandlebarTemplate> templates);
/**
* Returns a list of all registered Documentation%s.
*
@@ -97,18 +87,7 @@ public:
*/
static DocumentationEngine& ref();
/**
* Generates the documentation html file. Generated file will have embeded
* in it: HandlebarJS Templates (from _handlebarTemplates) and json (from
* \p data) along with the base template and js/css files from the source
* directory ${WEB}/documentation
*
* \param path The path to add
* \param data The JSON data that is written to the documentation
*/
void writeDocumentationHtml(const std::string& path, std::string data);
std::string generateJson() const override;
std::string generateJson() const;
nlohmann::json generateJsonJson() const;
@@ -116,12 +95,9 @@ private:
/// The list of all Documentation%s that are stored by the DocumentationEngine
std::vector<Documentation> _documentations;
/// The list of templates to render the documentation with.
std::vector<HandlebarTemplate> _handlebarTemplates;
static DocumentationEngine* _instance;
};
} // namespace openspace::documentation
#define DocEng (openspace::documentation::DocumentationEngine::ref())

View File

@@ -1,100 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2023 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___DOCUMENTATIONGENERATOR___H__
#define __OPENSPACE_CORE___DOCUMENTATIONGENERATOR___H__
#include <string>
#include <vector>
namespace openspace {
/*
* This abstract class is used for instances when another class has the ability to
* generate a Handlebar generated documentation file that contains valuable information
* for the user. Instances of this are the DocumentationEngine results, the list of
* Property%s generated by the Scene, or the FactoryEngine results. The documentation is
* generated through the writeDocumentation method.
*
* The concrete subclass needs to overload the generateJson class that will return the
* Json that is parsed by Handlebar to generate the webpage.
*
* A list of Handlebar templates, the variable name for the result of the generateJson
* method, and the Javascript file that contains additional logic is passed in the
* constructor.
*/
class DocumentationGenerator {
public:
/// This struct contains a single Handlebar template, with the name and the filename
struct HandlebarTemplate {
std::string name; ///< The name of the Handlebar template defined in #filename
std::string filename; ///< The filename referenced in the #name
};
/**
* The constructor that is used to set the member variables later used in the
* writeDocumentation method.
*
* \param name The name of the written documentation
* \param jsonName The variable name of the value generated by the generateJson
* \param handlebarTemplates A list of Handlebar templates that is added to the
* documentation file
*
* \pre name must not be empty
* \pre jsonName must not be empty
* \pre Each handlebarTemplates' `name` must not be empty
* \pre javascriptFilename must not be empty
*/
DocumentationGenerator(std::string name, std::string jsonName,
std::vector<HandlebarTemplate> handlebarTemplates);
/// Default constructor
virtual ~DocumentationGenerator() = default;
//getter for handlebar templates
std::vector<HandlebarTemplate> templatesToRegister();
//getter for identifier
std::string jsonName();
/**
* This abstract method is used by concrete subclasses to provide the actual data that
* is used in the documentation written by this DocumentationGenerator class. The JSON
* string returned by this function will be stored in the variable with the
* `jsonName` as passed in the constructor.
*
* \return A JSON script that is parsed and stored in the variable passed in the
* DocumentationGenerator constructor
*/
virtual std::string generateJson() const = 0;
private:
const std::string _name;
const std::string _jsonName;
const std::vector<HandlebarTemplate> _handlebarTemplates;
};
} // namespace openspace
#endif // __OPENSPACE_CORE___DOCUMENTATIONGENERATOR___H__

View File

@@ -25,8 +25,6 @@
#ifndef __OPENSPACE_CORE___KEYBINDINGMANAGER___H__
#define __OPENSPACE_CORE___KEYBINDINGMANAGER___H__
#include <openspace/documentation/documentationgenerator.h>
#include <openspace/util/keys.h>
namespace openspace {
@@ -38,7 +36,7 @@ namespace openspace::scripting { struct LuaLibrary; }
namespace openspace::interaction {
class KeybindingManager : public DocumentationGenerator {
class KeybindingManager {
public:
KeybindingManager();
@@ -55,8 +53,7 @@ public:
void keyboardCallback(Key key, KeyModifier modifier, KeyAction action);
std::string generateJson() const override;
nlohmann::json generateJsonJson() const;
nlohmann::json generateJson() const;
const std::multimap<KeyWithModifier, std::string>& keyBindings() const;

View File

@@ -25,7 +25,6 @@
#ifndef __OPENSPACE_CORE___MISSIONMANAGER___H__
#define __OPENSPACE_CORE___MISSIONMANAGER___H__
#include <openspace/documentation/documentationgenerator.h>
#include <openspace/mission/mission.h>
#include <ghoul/misc/assert.h>

View File

@@ -25,8 +25,6 @@
#ifndef __OPENSPACE_CORE___PROPERTYOWNER___H__
#define __OPENSPACE_CORE___PROPERTYOWNER___H__
#include <openspace/documentation/documentationgenerator.h>
#include <openspace/json.h>
#include <map>
#include <string>
@@ -49,7 +47,7 @@ class Property;
* (`.`), the first name before the separator will be used as a subOwner's name and the
* search will proceed recursively.
*/
class PropertyOwner : public DocumentationGenerator {
class PropertyOwner {
public:
/// The separator that is used while accessing the properties and/or sub-owners
static constexpr char URISeparator = '.';
@@ -76,7 +74,7 @@ public:
* The destructor will remove all Propertys and PropertyOwners it owns along with
* itself.
*/
virtual ~PropertyOwner() override;
virtual ~PropertyOwner();
/**
* Sets the identifier for this PropertyOwner. If the PropertyOwner does not have an
@@ -297,9 +295,7 @@ public:
void removeTag(const std::string& tag);
// Generate JSON for documentation
std::string generateJson() const override;
nlohmann::json generateJsonJson() const;
nlohmann::json generateJson() const;
protected:
/// The unique identifier of this PropertyOwner

View File

@@ -25,18 +25,16 @@
#ifndef __OPENSPACE_CORE___SCENELICENSEWRITER___H__
#define __OPENSPACE_CORE___SCENELICENSEWRITER___H__
#include <openspace/documentation/documentationgenerator.h>
#include <openspace/json.h>
#include <vector>
namespace openspace {
class SceneLicenseWriter : public DocumentationGenerator {
class SceneLicenseWriter {
public:
SceneLicenseWriter();
std::string generateJson() const override;
nlohmann::json generateJsonJson() const;
nlohmann::json generateJsonList() const;
nlohmann::json generateJsonGroupedByLicense() const;
};
} // namespace openspace

View File

@@ -26,7 +26,6 @@
#define __OPENSPACE_CORE___SCRIPTENGINE___H__
#include <openspace/util/syncable.h>
#include <openspace/documentation/documentationgenerator.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/json.h>
#include <ghoul/lua/luastate.h>
@@ -49,7 +48,7 @@ namespace openspace::scripting {
* `openspace` namespace prefix in Lua. The same functions can be exposed to
* other Lua states by passing them to the #initializeLuaState method.
*/
class ScriptEngine : public Syncable, public DocumentationGenerator {
class ScriptEngine : public Syncable {
public:
using ScriptCallback = std::function<void(ghoul::Dictionary)>;
BooleanType(RemoteScripting);
@@ -95,8 +94,7 @@ public:
std::vector<std::string> allLuaFunctions() const;
std::string generateJson() const override;
nlohmann::json generateJsonJson() const;
nlohmann::json generateJson() const;
private:
BooleanType(Replace);

View File

@@ -25,8 +25,6 @@
#ifndef __OPENSPACE_CORE___FACTORYMANAGER___H__
#define __OPENSPACE_CORE___FACTORYMANAGER___H__
#include <openspace/documentation/documentationgenerator.h>
#include <openspace/json.h>
#include <ghoul/misc/exception.h>
#include <ghoul/misc/templatefactory.h>
@@ -39,7 +37,7 @@ namespace openspace {
* them available through the #addFactory and #factory methods. Each
* ghoul::TemplateFactory can only be added once and can be accessed by its type.
*/
class FactoryManager : public DocumentationGenerator {
class FactoryManager {
public:
/// This exception is thrown if the ghoul::TemplateFactory could not be found in the
/// #factory method
@@ -109,8 +107,7 @@ public:
template <class T>
ghoul::TemplateFactory<T>* factory() const;
std::string generateJson() const override;
nlohmann::json generateJsonJson() const;
nlohmann::json generateJson() const;
private:
/// Singleton member for the Factory Manager

View File

@@ -26,6 +26,7 @@
#define __OPENSPACE_CORE___JSON_HELPER___H__
#include <string>
#include <openspace/json.h>
namespace openspace {
@@ -65,6 +66,16 @@ std::string formatJsonNumber(double d);
template <typename T>
std::string formatJson(T value);
/**
* Sort a json object that is an array of objects with the structure
* [ key = {}, key = {} ...]. Sorts it by the provided key
*
* \param json The json to sort
* \param key The key the json should be sorted by
* \return The sorted JSON
*/
void sortJson(nlohmann::json& json, const std::string& key);
} // namespace openspace
#include "json_helper.inl"

View File

@@ -47,21 +47,19 @@ void DocumentationTopic::handleJson(const nlohmann::json& json) {
// Do not parse generated json. Instead implement ability to get
// ghoul::Dictionary objects from ScriptEngine, FactoryManager, and KeybindingManager.
if (requestedType == "lua") {
response = json::parse(global::scriptEngine->generateJson());
response = global::scriptEngine->generateJson();
}
else if (requestedType == "factories") {
response = json::parse(FactoryManager::ref().generateJson());
response = FactoryManager::ref().generateJson();
}
else if (requestedType == "keyboard") {
response = json::parse(global::keybindingManager->generateJson());
response = global::keybindingManager->generateJson();
}
else if (requestedType == "asset") {
response = json::parse(global::keybindingManager->generateJson());
response = global::keybindingManager->generateJson();
}
else if (requestedType == "meta") {
std::string docs = SceneLicenseWriter().generateJson();
nlohmann::json parsedDocs = json::parse(docs);
response = parsedDocs;
response = SceneLicenseWriter().generateJsonList();
}
_connection->sendJson(wrappedPayload(response));

View File

@@ -30,7 +30,6 @@ set(OPENSPACE_SOURCE
documentation/core_registration.cpp
documentation/documentation.cpp
documentation/documentationengine.cpp
documentation/documentationgenerator.cpp
documentation/verifier.cpp
engine/configuration.cpp
engine/downloadmanager.cpp
@@ -212,7 +211,6 @@ set(OPENSPACE_HEADER
${PROJECT_SOURCE_DIR}/include/openspace/documentation/core_registration.h
${PROJECT_SOURCE_DIR}/include/openspace/documentation/documentation.h
${PROJECT_SOURCE_DIR}/include/openspace/documentation/documentationengine.h
${PROJECT_SOURCE_DIR}/include/openspace/documentation/documentationgenerator.h
${PROJECT_SOURCE_DIR}/include/openspace/documentation/verifier.h
${PROJECT_SOURCE_DIR}/include/openspace/documentation/verifier.inl
${PROJECT_SOURCE_DIR}/include/openspace/engine/configuration.h

View File

@@ -55,15 +55,7 @@ DocumentationEngine::DuplicateDocumentationException::DuplicateDocumentationExce
, documentation(std::move(doc))
{}
DocumentationEngine::DocumentationEngine()
: DocumentationGenerator(
"Top Level",
"toplevel",
{
{ "toplevelTemplate", "${WEB}/documentation/toplevel.hbs" },
}
)
{}
DocumentationEngine::DocumentationEngine() {}
void DocumentationEngine::initialize() {
ghoul_assert(!isInitialized(), "DocumentationEngine is already initialized");
@@ -180,142 +172,7 @@ void DocumentationEngine::addDocumentation(Documentation documentation) {
}
}
void DocumentationEngine::addHandlebarTemplates(std::vector<HandlebarTemplate> templates)
{
_handlebarTemplates.insert(
_handlebarTemplates.end(),
templates.begin(), templates.end()
);
}
std::vector<Documentation> DocumentationEngine::documentations() const {
return _documentations;
}
void DocumentationEngine::writeDocumentationHtml(const std::string& path,
std::string data)
{
ZoneScoped;
std::ifstream handlebarsInput;
handlebarsInput.exceptions(~std::ofstream::goodbit);
handlebarsInput.open(absPath(HandlebarsFilename));
const std::string handlebarsContent = std::string(
std::istreambuf_iterator<char>(handlebarsInput),
std::istreambuf_iterator<char>()
);
std::ifstream jsInput;
jsInput.exceptions(~std::ofstream::goodbit);
jsInput.open(absPath(JsFilename));
const std::string jsContent = std::string(
std::istreambuf_iterator<char>(jsInput),
std::istreambuf_iterator<char>()
);
std::ifstream bootstrapInput;
bootstrapInput.exceptions(~std::ofstream::goodbit);
bootstrapInput.open(absPath(BootstrapFilename));
const std::string bootstrapContent = std::string(
std::istreambuf_iterator<char>(bootstrapInput),
std::istreambuf_iterator<char>()
);
std::ifstream cssInput;
cssInput.exceptions(~std::ofstream::goodbit);
cssInput.open(absPath(CssFilename));
const std::string cssContent = std::string(
std::istreambuf_iterator<char>(cssInput),
std::istreambuf_iterator<char>()
);
std::string filename = path + ("index.html");
std::ofstream file;
file.exceptions(~std::ofstream::goodbit);
file.open(filename);
// We probably should escape backslashes here?
file << "<!DOCTYPE html>" << '\n'
<< "<html>" << '\n'
<< " " << "<head>" << '\n';
//write handlebar templates to htmlpage as script elements (as per hb)
for (const HandlebarTemplate& t : _handlebarTemplates) {
const char* Type = "text/x-handlebars-template";
file << " <script id=\"" << t.name << "\" type=\"" << Type << "\">";
file << '\n';
std::ifstream templateFilename(absPath(t.filename));
std::string templateContent(
std::istreambuf_iterator<char>{templateFilename},
std::istreambuf_iterator<char>{}
);
file << templateContent << "\n </script>" << '\n';
}
//write main template
file << " <script id=\"mainTemplate\" type=\"text/x-handlebars-template\">";
file << '\n';
std::ifstream templateFilename(absPath("${WEB}/documentation/main.hbs"));
std::string templateContent(
std::istreambuf_iterator<char>{templateFilename},
std::istreambuf_iterator<char>{}
);
file << templateContent << " </script>" << '\n';
//write scripte to register templates dynamically
file << " <script type=\"text/javascript\">" << '\n';
file << " templates = [];" << '\n';
file << " registerTemplates = function() {" << '\n';
for (const HandlebarTemplate& t : _handlebarTemplates) {
std::string nameOnly = t.name.substr(0, t.name.length() - 8); //-8 for Template
file << "\t\t\t\tvar " << t.name;
file << "Element = document.getElementById('" << t.name << "');" << '\n';
file << "\t\t\t\tHandlebars.registerPartial('" << nameOnly << "', ";
file << t.name << "Element.innerHTML);" << '\n';
file << "\t\t\t\ttemplates['" << nameOnly << "'] = Handlebars.compile(";
file << t.name << "Element.innerHTML);" << '\n';
}
file << "\t\t\t}" << '\n';
file << "\t\t</script>" << '\n';
const std::string DataId = "data";
const std::string Version =
"[" +
std::to_string(OPENSPACE_VERSION_MAJOR) + "," +
std::to_string(OPENSPACE_VERSION_MINOR) + "," +
std::to_string(OPENSPACE_VERSION_PATCH) +
"]";
file
<< " " << "<script id=\"" << DataId
<< "\" type=\"text/application/json\">" << '\n'
<< " " << std::move(data) << '\n'
<< " " << "</script>" << '\n';
file
<< " " << "<script>" << '\n'
<< " " << jsContent << '\n'
<< " " << "var documentation = parseJson('" << DataId << "').documentation;\n"
<< " " << "var version = " << Version << ";" << '\n'
<< " " << "var currentDocumentation = documentation[0];" << '\n'
<< " " << handlebarsContent << '\n'
<< " " << "</script>" << '\n'
<< " " << "<style type=\"text/css\">" << '\n'
<< " " << cssContent << '\n'
<< " " << bootstrapContent << '\n'
<< " " << "</style>" << '\n'
<< " " << "<title>OpenSpace Documentation</title>" << '\n'
<< " " << "</head>" << '\n'
<< " " << "<body>" << '\n'
<< " " << "</body>" << '\n'
<< "</html>" << '\n';
}
} // namespace openspace::documentation

View File

@@ -22,40 +22,8 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/documentation/documentationgenerator.h>
#include <openspace/openspace.h>
#include <openspace/util/time.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/misc/invariants.h>
#include <fstream>
namespace openspace {
DocumentationGenerator::DocumentationGenerator(std::string name,
std::string jsonName,
std::vector<HandlebarTemplate> handlebarTemplates)
: _name(std::move(name))
, _jsonName(std::move(jsonName))
, _handlebarTemplates(std::move(handlebarTemplates))
{
ghoul_precondition(!_name.empty(), "name must not be empty");
ghoul_precondition(!_jsonName.empty(), "jsonName must not be empty");
for (const HandlebarTemplate& t : _handlebarTemplates) {
(void)t; // Unused variable in Release mode
ghoul_precondition(!t.name.empty(), "name must not be empty");
ghoul_precondition(!t.filename.empty(), "filename must not be empty");
}
}
std::vector<DocumentationGenerator::HandlebarTemplate>
DocumentationGenerator::templatesToRegister()
{
return _handlebarTemplates;
}
std::string DocumentationGenerator::jsonName() {
return _jsonName;
}
} // namespace openspace

View File

@@ -1039,47 +1039,34 @@ void OpenSpaceEngine::writeDocumentation() {
// Start the async requests as soon as possible so they are finished when we need them
std::future<nlohmann::json> settings = std::async(
&properties::PropertyOwner::generateJsonJson,
&properties::PropertyOwner::generateJson,
global::rootPropertyOwner
);
std::future<nlohmann::json> scene = std::async(
&properties::PropertyOwner::generateJsonJson,
&properties::PropertyOwner::generateJson,
_scene.get()
);
DocEng.addHandlebarTemplates(global::scriptEngine->templatesToRegister());
DocEng.addHandlebarTemplates(FactoryManager::ref().templatesToRegister());
DocEng.addHandlebarTemplates(DocEng.templatesToRegister());
nlohmann::json scripting;
scripting["Name"] = "Scripting API";
scripting["Data"] = global::scriptEngine->generateJsonJson();
nlohmann::json factory;
factory["Name"] = "Asset Types";
factory["Data"] = FactoryManager::ref().generateJsonJson();
nlohmann::json keybindings;
keybindings["Name"] = "Keybindings";
keybindings["Keybindings"] = global::keybindingManager->generateJsonJson();
SceneLicenseWriter writer;
nlohmann::json license;
license["Name"] = "Licenses";
license["Data"] = writer.generateJsonJson();
nlohmann::json sceneProperties;
sceneProperties["Name"] = "Settings";
sceneProperties["Data"] = settings.get();
nlohmann::json sceneGraph;
sceneGraph["Name"] = "Scene";
sceneGraph["Data"] = scene.get();
nlohmann::json scripting = global::scriptEngine->generateJson();
nlohmann::json factory = FactoryManager::ref().generateJson();
nlohmann::json keybindings = global::keybindingManager->generateJson();
nlohmann::json license = writer.generateJsonGroupedByLicense();
nlohmann::json sceneProperties = settings.get();
nlohmann::json sceneGraph = scene.get();
sceneProperties["name"] = "Settings";
sceneGraph["name"] = "Scene";
// Add this here so that the generateJson function is the same as before to ensure
// backwards compatibility
nlohmann::json scriptingResult;
scriptingResult["name"] = "Scripting API";
scriptingResult["data"] = scripting;
nlohmann::json documentation = {
sceneGraph, sceneProperties, keybindings, license, scripting, factory
sceneGraph, sceneProperties, keybindings, license, scriptingResult, factory
};
nlohmann::json result;

View File

@@ -38,39 +38,7 @@
namespace openspace::interaction {
void sortJson(nlohmann::json& json) {
std::sort(
json.begin(),
json.end(),
[](const nlohmann::json& lhs, const nlohmann::json& rhs) {
std::string lhsString = lhs["Name"];
std::string rhsString = rhs["Name"];
std::transform(
lhsString.begin(),
lhsString.end(),
lhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
std::transform(
rhsString.begin(),
rhsString.end(),
rhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
return rhsString > lhsString;
});
}
KeybindingManager::KeybindingManager()
: DocumentationGenerator(
"Keybindings",
"keybinding",
{
{ "keybindingTemplate", "${WEB}/documentation/keybinding.hbs" }
}
)
{}
KeybindingManager::KeybindingManager() {}
void KeybindingManager::keyboardCallback(Key key, KeyModifier modifier, KeyAction action)
{
@@ -143,41 +111,23 @@ const std::multimap<KeyWithModifier, std::string>& KeybindingManager::keyBinding
return _keyLua;
}
std::string KeybindingManager::generateJson() const {
ZoneScoped;
std::stringstream json;
json << "[";
bool first = true;
for (const std::pair<const KeyWithModifier, std::string>& p : _keyLua) {
if (!first) {
json << ",";
}
first = false;
json << "{";
json << R"("key": ")" << ghoul::to_string(p.first) << "\",";
json << R"("action": ")" << p.second << "\"";
json << "}";
}
json << "]";
return json.str();
}
nlohmann::json KeybindingManager::generateJsonJson() const {
nlohmann::json KeybindingManager::generateJson() const {
ZoneScoped;
nlohmann::json json;
for (const std::pair<const KeyWithModifier, std::string>& p : _keyLua) {
nlohmann::json keybind;
keybind["Name"] = ghoul::to_string(p.first);
keybind["Action"] = p.second;
keybind["name"] = ghoul::to_string(p.first);
keybind["action"] = p.second;
json.push_back(std::move(keybind));
}
sortJson(json);
sortJson(json, "name");
return json;
nlohmann::json result;
result["name"] = "Keybindings";
result["keybindings"] = json;
return result;
}
scripting::LuaLibrary KeybindingManager::luaLibrary() {

View File

@@ -41,62 +41,39 @@
namespace {
constexpr std::string_view _loggerCat = "PropertyOwner";
void sortJson(nlohmann::json& json) {
std::sort(
json.begin(),
json.end(),
[](const nlohmann::json& lhs, const nlohmann::json& rhs) {
std::string lhsString = lhs["Name"];
std::string rhsString = rhs["Name"];
std::transform(
lhsString.begin(),
lhsString.end(),
lhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
std::transform(
rhsString.begin(),
rhsString.end(),
rhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
return rhsString > lhsString;
});
}
nlohmann::json createJson(openspace::properties::PropertyOwner* owner) {
ZoneScoped
using namespace openspace;
nlohmann::json json;
json["Name"] = owner->identifier();
json["name"] = !owner->guiName().empty() ? owner->guiName() : owner->identifier();
json["Description"] = owner->description();
json["Properties"] = nlohmann::json::array();
json["PropertyOwners"] = nlohmann::json::array();
json["Type"] = owner->type();
json["Tags"] = owner->tags();
json["description"] = owner->description();
json["properties"] = nlohmann::json::array();
json["propertyOwners"] = nlohmann::json::array();
json["type"] = owner->type();
json["tags"] = owner->tags();
const std::vector<properties::Property*>& properties = owner->properties();
for (properties::Property* p : properties) {
nlohmann::json propertyJson;
propertyJson["Name"] = p->identifier();
propertyJson["Type"] = p->className();
propertyJson["URI"] = p->fullyQualifiedIdentifier();
propertyJson["Gui Name"] = p->guiName();
propertyJson["Description"] = p->description();
std::string name = !p->guiName().empty() ? p->guiName() : p->identifier();
propertyJson["name"] = name;
propertyJson["type"] = p->className();
propertyJson["uri"] = p->fullyQualifiedIdentifier();
propertyJson["identifier"] = p->identifier();
propertyJson["description"] = p->description();
json["Properties"].push_back(propertyJson);
json["properties"].push_back(propertyJson);
}
sortJson(json["Properties"]);
sortJson(json["properties"], "name");
auto propertyOwners = owner->propertySubOwners();
for (properties::PropertyOwner* o : propertyOwners) {
nlohmann::json propertyOwner;
json["PropertyOwners"].push_back(createJson(o));
json["propertyOwners"].push_back(createJson(o));
}
sortJson(json["PropertyOwners"]);
sortJson(json["propertyOwners"], "name");
return json;
}
@@ -105,16 +82,7 @@ namespace {
namespace openspace::properties {
PropertyOwner::PropertyOwner(PropertyOwnerInfo info)
: DocumentationGenerator(
"Property Owners",
"propertyOwners",
{
{ "propertyOwnersTemplate","${WEB}/documentation/propertyowners.hbs" },
{ "propertyTemplate","${WEB}/documentation/property.hbs" },
{ "propertylistTemplate","${WEB}/documentation/propertylist.hbs" }
}
)
, _identifier(std::move(info.identifier))
: _identifier(std::move(info.identifier))
, _guiName(std::move(info.guiName))
, _description(std::move(info.description))
{
@@ -418,31 +386,25 @@ void PropertyOwner::removeTag(const std::string& tag) {
_tags.erase(std::remove(_tags.begin(), _tags.end(), tag), _tags.end());
}
std::string PropertyOwner::generateJson() const {
ZoneScoped;
nlohmann::json json;
std::vector<PropertyOwner*> subOwners = propertySubOwners();
for (PropertyOwner* owner : subOwners) {
json["Data"].push_back(createJson(owner));
}
return json.dump();
}
nlohmann::json PropertyOwner::generateJsonJson() const {
nlohmann::json PropertyOwner::generateJson() const {
ZoneScoped
nlohmann::json json;
std::vector<PropertyOwner*> subOwners = propertySubOwners();
for (PropertyOwner* owner : subOwners) {
if (owner->identifier() != "Scene") {
json.push_back(createJson(owner));
nlohmann::json jsonOwner = createJson(owner);
json.push_back(jsonOwner);
}
}
sortJson(json);
sortJson(json, "name");
return json;
nlohmann::json result;
result["name"] = "propertyOwner";
result["data"] = json;
return result;
}
} // namespace openspace::properties

View File

@@ -36,41 +36,9 @@
namespace openspace {
SceneLicenseWriter::SceneLicenseWriter()
: DocumentationGenerator(
"Scene Licenses",
"sceneLicense",
{
{ "sceneLicenseTemplate", "${WEB}/documentation/scenelicense.hbs" }
}
)
{}
SceneLicenseWriter::SceneLicenseWriter() {}
void sortJson(nlohmann::json& json) {
std::sort(
json.begin(),
json.end(),
[](const nlohmann::json& lhs, const nlohmann::json& rhs) {
std::string lhsString = lhs["Name"];
std::string rhsString = rhs["Name"];
std::transform(
lhsString.begin(),
lhsString.end(),
lhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
std::transform(
rhsString.begin(),
rhsString.end(),
rhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
return rhsString > lhsString;
});
}
nlohmann::json SceneLicenseWriter::generateJsonJson() const {
nlohmann::json SceneLicenseWriter::generateJsonGroupedByLicense() const {
nlohmann::json json;
std::vector<const Asset*> assets =
@@ -89,14 +57,14 @@ nlohmann::json SceneLicenseWriter::generateJsonJson() const {
if (global::profile->meta.has_value()) {
metaTotal++;
nlohmann::json metaJson;
metaJson["Name"] = "Profile";
metaJson["ProfileName"] = global::profile->meta->name.value_or("");
metaJson["Version"] = global::profile->meta->version.value_or("");
metaJson["Description"] = global::profile->meta->description.value_or("");
metaJson["Author"] = global::profile->meta->author.value_or("");
metaJson["Url"] = global::profile->meta->url.value_or("");
metaJson["License"] = global::profile->meta->license.value_or("");
metaJson["Type"] = "license";
metaJson["name"] = "Profile";
metaJson["profileName"] = global::profile->meta->name.value_or("");
metaJson["version"] = global::profile->meta->version.value_or("");
metaJson["description"] = global::profile->meta->description.value_or("");
metaJson["author"] = global::profile->meta->author.value_or("");
metaJson["url"] = global::profile->meta->url.value_or("");
metaJson["license"] = global::profile->meta->license.value_or("");
metaJson["type"] = "license";
json.push_back(std::move(metaJson));
}
@@ -106,102 +74,69 @@ nlohmann::json SceneLicenseWriter::generateJsonJson() const {
nlohmann::json assetJson;
if (!meta.has_value()) {
assetJson["Name"] = "";
assetJson["Version"] = "";
assetJson["Description"] = "";
assetJson["Author"] = "";
assetJson["Url"] = "";
assetJson["License"] = "No license";
assetJson["Identifiers"] = "";
assetJson["Path"] = asset->path().string();
assetJson["name"] = "";
assetJson["version"] = "";
assetJson["description"] = "";
assetJson["author"] = "";
assetJson["url"] = "";
assetJson["license"] = "No license";
assetJson["identifiers"] = "";
assetJson["path"] = asset->path().string();
assetLicenses["No license"].push_back(assetJson);
assetLicenses["noLicense"].push_back(assetJson);
}
else {
std::string license = meta->license == "" ? "No license" : meta->license;
assetJson["Name"] = meta->name;
assetJson["Version"] = meta->version;
assetJson["Description"] = meta->description;
assetJson["Author"] = meta->author;
assetJson["Url"] = meta->url;
assetJson["License"] = license;
assetJson["Identifiers"] = meta->identifiers;
assetJson["Path"] = asset->path().string();
std::string license = meta->license == "" ? "No License" : meta->license;
assetJson["name"] = meta->name;
assetJson["version"] = meta->version;
assetJson["description"] = meta->description;
assetJson["author"] = meta->author;
assetJson["url"] = meta->url;
assetJson["license"] = license;
assetJson["identifiers"] = meta->identifiers;
assetJson["path"] = asset->path().string();
assetLicenses[license].push_back(assetJson);
}
}
nlohmann::json assetsJson;
assetsJson["Name"] = "Assets";
assetsJson["Type"] = "Licenses";
assetsJson["name"] = "Assets";
assetsJson["type"] = "Licenses";
for (const std::pair<std::string, nlohmann::json>& assetLicense : assetLicenses) {
nlohmann::json entry;
entry["Name"] = assetLicense.first;
entry["Assets"] = assetLicense.second;
sortJson(entry["Assets"]);
assetsJson["Licenses"].push_back(entry);
entry["name"] = assetLicense.first;
entry["assets"] = assetLicense.second;
sortJson(entry["assets"], "name");
assetsJson["licenses"].push_back(entry);
}
json.push_back(assetsJson);
return json;
nlohmann::json result;
result["name"] = "Licenses";
result["data"] = json;
return result;
}
std::string SceneLicenseWriter::generateJson() const {
ZoneScoped;
nlohmann::json SceneLicenseWriter::generateJsonList() const {
nlohmann::json json;
std::stringstream json;
json << "[";
if (global::profile->meta.has_value()) {
nlohmann::json profile;
profile["name"] = global::profile->meta->name.value_or("");
profile["version"] = global::profile->meta->version.value_or("");
profile["description"] = global::profile->meta->description.value_or("");
profile["author"] = global::profile->meta->author.value_or("");
profile["url"] = global::profile->meta->url.value_or("");
profile["license"] = global::profile->meta->license.value_or("");
json.push_back(profile);
}
std::vector<const Asset*> assets =
global::openSpaceEngine->assetManager().allAssets();
int metaTotal = 0;
int metaCount = 0;
for (const Asset* asset : assets) {
std::optional<Asset::MetaInformation> meta = asset->metaInformation();
if (!meta.has_value()) {
continue;
}
metaTotal++;
}
if (global::profile->meta.has_value()) {
metaTotal++;
constexpr std::string_view replStr = R"("{}": "{}", )";
constexpr std::string_view replStr2 = R"("{}": "{}")";
json << "{";
json << fmt::format(
replStr,
"name", escapedJson(global::profile->meta->name.value_or(""))
);
json << fmt::format(
replStr,
"version", escapedJson(global::profile->meta->version.value_or(""))
);
json << fmt::format(
replStr,
"description", escapedJson(global::profile->meta->description.value_or(""))
);
json << fmt::format(
replStr,
"author", escapedJson(global::profile->meta->author.value_or(""))
);
json << fmt::format(
replStr,
"url", escapedJson(global::profile->meta->url.value_or(""))
);
json << fmt::format(
replStr2,
"license", escapedJson(global::profile->meta->license.value_or(""))
);
json << "}";
if (++metaCount != metaTotal) {
json << ",";
}
}
for (const Asset* asset : assets) {
std::optional<Asset::MetaInformation> meta = asset->metaInformation();
@@ -209,27 +144,18 @@ std::string SceneLicenseWriter::generateJson() const {
continue;
}
constexpr std::string_view replStr = R"("{}": "{}", )";
constexpr std::string_view replStr2 = R"("{}": "{}")";
json << "{";
json << fmt::format(replStr, "name", escapedJson(meta->name));
json << fmt::format(replStr, "version", escapedJson(meta->version));
json << fmt::format(replStr, "description", escapedJson(meta->description));
json << fmt::format(replStr, "author", escapedJson(meta->author));
json << fmt::format(replStr, "url", escapedJson(meta->url));
json << fmt::format(replStr, "license", escapedJson(meta->license));
json << fmt::format(replStr, "identifiers", escapedJson(meta->identifiers));
json << fmt::format(replStr2, "path", escapedJson(asset->path().string()));
json << "}";
nlohmann::json assetJson;
assetJson["name"] = meta->name;
assetJson["version"] = meta->version;
assetJson["description"] = meta->description;
assetJson["author"] = meta->author;
assetJson["url"] = meta->url;
assetJson["license"] = meta->license;
assetJson["identifiers"] = meta->identifiers;
assetJson["path"] = asset->path().string();
metaCount++;
if (metaCount != metaTotal) {
json << ",";
}
json.push_back(assetJson);
}
json << "]";
return json.str();
return json;
}
} // namespace openspace

View File

@@ -81,149 +81,43 @@ namespace {
return result;
}
void sortJson(nlohmann::json& json) {
std::sort(
json.begin(),
json.end(),
[](const nlohmann::json& lhs, const nlohmann::json& rhs) {
std::string lhsString = lhs["Name"];
std::string rhsString = rhs["Name"];
std::transform(
lhsString.begin(),
lhsString.end(),
lhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
std::transform(
rhsString.begin(),
rhsString.end(),
rhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
return rhsString > lhsString;
});
}
nlohmann::json toJson(const openspace::scripting::LuaLibrary::Function& f) {
nlohmann::json toJson(const openspace::scripting::LuaLibrary::Function& f,
bool includeSourceLocation)
{
using namespace openspace;
using namespace openspace::scripting;
nlohmann::json function;
function["Name"] = f.name;
function["name"] = f.name;
nlohmann::json arguments = nlohmann::json::array();
for (const LuaLibrary::Function::Argument& arg : f.arguments) {
nlohmann::json argument;
argument["Name"] = arg.name;
argument["Type"] = arg.type;
argument["Default Value"] = arg.defaultValue.value_or("");
argument["name"] = arg.name;
argument["type"] = arg.type;
argument["defaultValue"] = arg.defaultValue.value_or("");
arguments.push_back(argument);
}
function["Arguments"] = arguments;
function["Return Type"] = f.returnType;
function["Help"] = f.helpText;
function["arguments"] = arguments;
function["returnType"] = f.returnType;
function["help"] = f.helpText;
if (includeSourceLocation) {
nlohmann::json sourceLocation;
sourceLocation["file"] = f.sourceLocation.file;
sourceLocation["line"] = f.sourceLocation.line;
function["sourceLocation"] = sourceLocation;
}
return function;
}
void toJson(const openspace::scripting::LuaLibrary& library, std::stringstream& json)
{
constexpr std::string_view replStr = R"("{}": "{}", )";
constexpr std::string_view replStr2 = R"("{}": "{}")";
using namespace openspace;
using namespace openspace::scripting;
json << "{";
json << fmt::format(replStr, "library", library.name);
json << "\"functions\": [";
for (const LuaLibrary::Function& f : library.functions) {
json << "{";
json << fmt::format(replStr, "name", f.name);
json << "\"arguments\": [";
for (const LuaLibrary::Function::Argument& arg : f.arguments) {
json << "{";
json << fmt::format(replStr, "name", escapedJson(arg.name));
json << fmt::format(replStr, "type", escapedJson(arg.type));
json << fmt::format(
replStr2, "defaultValue", escapedJson(arg.defaultValue.value_or(""))
);
json << "}";
if (&arg != &f.arguments.back()) {
json << ",";
}
}
json << "],";
json << fmt::format(replStr, "returnType", escapedJson(f.returnType));
json << fmt::format(replStr, "help", escapedJson(f.helpText));
json << fmt::format(
"\"sourceLocation\": {{ \"file\": \"{}\", \"line\": {} }}",
escapedJson(f.sourceLocation.file), f.sourceLocation.line
);
json << "}";
if (&f != &library.functions.back() || !library.documentations.empty()) {
json << ",";
}
}
for (const LuaLibrary::Function& f : library.documentations) {
json << "{";
json << fmt::format(replStr, "name", f.name);
json << "\"arguments\": [";
for (const LuaLibrary::Function::Argument& arg : f.arguments) {
json << "{";
json << fmt::format(replStr, "name", escapedJson(arg.name));
json << fmt::format(replStr, "type", escapedJson(arg.type));
json << fmt::format(
replStr2, "defaultValue", escapedJson(arg.defaultValue.value_or(""))
);
json << "}";
if (&arg != &f.arguments.back()) {
json << ",";
}
}
json << "],";
json << fmt::format(replStr, "returnType", escapedJson(f.returnType));
json << fmt::format(replStr2, "help", escapedJson(f.helpText));
json << "}";
if (&f != &library.documentations.back()) {
json << ",";
}
}
json << "],";
json << "\"subLibraries\": [";
for (const LuaLibrary& sl : library.subLibraries) {
toJson(sl, json);
if (&sl != &library.subLibraries.back()) {
json << ",";
}
}
json << "]}";
}
#include "scriptengine_codegen.cpp"
} // namespace
namespace openspace::scripting {
ScriptEngine::ScriptEngine()
: DocumentationGenerator(
"Script Documentation",
"scripting",
{
{ "scriptingTemplate","${WEB}/documentation/scripting.hbs" },
}
)
{
//tracy::LuaRegister(_state);
}
ScriptEngine::ScriptEngine() {}
void ScriptEngine::initialize() {
ZoneScoped;
@@ -554,28 +448,7 @@ std::vector<std::string> ScriptEngine::allLuaFunctions() const {
return result;
}
std::string ScriptEngine::generateJson() const {
ZoneScoped;
// Create JSON
std::stringstream json;
json << "[";
bool first = true;
for (const LuaLibrary& l : _registeredLibraries) {
if (!first) {
json << ",";
}
first = false;
toJson(l, json);
}
json << "]";
return json.str();
}
nlohmann::json ScriptEngine::generateJsonJson() const {
nlohmann::json ScriptEngine::generateJson() const {
ZoneScoped
nlohmann::json json;
@@ -585,20 +458,26 @@ nlohmann::json ScriptEngine::generateJsonJson() const {
using namespace openspace::scripting;
nlohmann::json library;
std::string libraryName = l.name.empty() ? "openspace" : "openspace." + l.name;
library["Name"] = libraryName;
std::string libraryName = l.name;
// Keep the library key for backwards compatability
library["library"] = libraryName;
library["name"] = libraryName;
std::string os = "openspace";
library["fullName"] = libraryName.empty() ? os : os + "." + libraryName;
for (const LuaLibrary::Function& f : l.functions) {
library["Functions"].push_back(toJson(f));
bool hasSourceLocation = true;
library["functions"].push_back(toJson(f, hasSourceLocation));
}
for (const LuaLibrary::Function& f : l.documentations) {
library["Functions"].push_back(toJson(f));
bool hasSourceLocation = false;
library["functions"].push_back(toJson(f, hasSourceLocation));
}
sortJson(library["Functions"]);
sortJson(library["functions"], "name");
json.push_back(library);
sortJson(json);
sortJson(json, "library");
}
return json;
}

View File

@@ -42,43 +42,19 @@ namespace {
using namespace openspace;
using namespace openspace::documentation;
void sortJson(nlohmann::json& json) {
std::sort(
json.begin(),
json.end(),
[](const nlohmann::json& lhs, const nlohmann::json& rhs) {
std::string lhsString = lhs["Name"];
std::string rhsString = rhs["Name"];
std::transform(
lhsString.begin(),
lhsString.end(),
lhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
std::transform(
rhsString.begin(),
rhsString.end(),
rhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
return rhsString > lhsString;
});
}
nlohmann::json generateJsonDocumentation(const Documentation& d) {
nlohmann::json json;
json["Name"] = d.name;
json["Identifier"] = d.id;
json["Members"] = nlohmann::json::array();
json["name"] = d.name;
json["identifier"] = d.id;
json["members"] = nlohmann::json::array();
for (const DocumentationEntry& p : d.entries) {
nlohmann::json entry;
entry["Name"] = p.key;
entry["Optional"] = p.optional.value;
entry["Type"] = p.verifier->type();
entry["Documentation"] = p.documentation;
entry["name"] = p.key;
entry["optional"] = p.optional.value;
entry["type"] = p.verifier->type();
entry["documentation"] = p.documentation;
TableVerifier* tv = dynamic_cast<TableVerifier*>(p.verifier.get());
ReferencingVerifier* rv = dynamic_cast<ReferencingVerifier*>(p.verifier.get());
@@ -92,28 +68,28 @@ nlohmann::json generateJsonDocumentation(const Documentation& d) {
);
if (it == documentations.end()) {
entry["Reference"]["Found"] = false;
entry["reference"]["found"] = false;
}
else {
nlohmann::json reference;
reference["Found"] = true;
reference["Name"] = it->name;
reference["Identifier"] = rv->identifier;
reference["found"] = true;
reference["name"] = it->name;
reference["identifier"] = rv->identifier;
entry["Reference"] = reference;
entry["reference"] = reference;
}
}
else if (tv) {
nlohmann::json json = generateJsonDocumentation(tv->documentations);
// We have a TableVerifier, so we need to recurse
entry["Restrictions"] = json;
entry["restrictions"] = json;
}
else {
entry["Description"] = p.verifier->documentation();
entry["description"] = p.verifier->documentation();
}
json["Members"].push_back(entry);
json["members"].push_back(entry);
}
sortJson(json["Members"]);
sortJson(json["members"], "name");
return json;
}
@@ -130,15 +106,7 @@ FactoryManager::FactoryNotFoundError::FactoryNotFoundError(std::string t)
ghoul_assert(!type.empty(), "Type must not be empty");
}
FactoryManager::FactoryManager()
: DocumentationGenerator(
"Factory Documentation",
"factory",
{
{ "factoryTemplate", "${WEB}/documentation/factory.hbs" }
}
)
{}
FactoryManager::FactoryManager() {}
void FactoryManager::initialize() {
ghoul_assert(!_manager, "Factory Manager must not have been initialized");
@@ -172,32 +140,14 @@ FactoryManager& FactoryManager::ref() {
return *_manager;
}
std::string FactoryManager::generateJson() const {
nlohmann::json json;
for (const FactoryInfo& factoryInfo : _factories) {
nlohmann::json factory;
factory["Name"] = factoryInfo.name;
ghoul::TemplateFactoryBase* f = factoryInfo.factory.get();
const std::vector<std::string>& registeredClasses = f->registeredClasses();
for (const std::string& c : registeredClasses) {
json["Classes"].push_back(c);
}
json["Data"].push_back(factory);
}
return json.dump();
}
nlohmann::json FactoryManager::generateJsonJson() const {
nlohmann::json FactoryManager::generateJson() const {
nlohmann::json json;
std::vector<Documentation> docs = DocEng.documentations();
for (const FactoryInfo& factoryInfo : _factories) {
nlohmann::json factory;
factory["Name"] = factoryInfo.name;
factory["Identifier"] = "category" + factoryInfo.name;
factory["name"] = factoryInfo.name;
factory["identifier"] = "category" + factoryInfo.name;
ghoul::TemplateFactoryBase* f = factoryInfo.factory.get();
// Add documentation about base class
@@ -209,15 +159,15 @@ nlohmann::json FactoryManager::generateJsonJson() const {
});
if (factoryDoc != docs.end()) {
nlohmann::json documentation = generateJsonDocumentation(*factoryDoc);
factory["Classes"].push_back(documentation);
factory["classes"].push_back(documentation);
// Remove documentation from list check at the end if all docs got put in
docs.erase(factoryDoc);
}
else {
nlohmann::json documentation;
documentation["Name"] = factoryInfo.name;
documentation["Identifier"] = factoryInfo.name;
factory["Classes"].push_back(documentation);
documentation["name"] = factoryInfo.name;
documentation["identifier"] = factoryInfo.name;
factory["classes"].push_back(documentation);
}
// Add documentation about derived classes
@@ -231,32 +181,37 @@ nlohmann::json FactoryManager::generateJsonJson() const {
});
if (found != docs.end()) {
nlohmann::json documentation = generateJsonDocumentation(*found);
factory["Classes"].push_back(documentation);
factory["classes"].push_back(documentation);
docs.erase(found);
}
else {
nlohmann::json documentation;
documentation["Name"] = c;
documentation["Identifier"] = c;
factory["Classes"].push_back(documentation);
documentation["name"] = c;
documentation["identifier"] = c;
factory["classes"].push_back(documentation);
}
}
sortJson(factory["Classes"]);
sortJson(factory["classes"], "name");
json.push_back(factory);
}
// Add all leftover docs
nlohmann::json leftovers;
leftovers["Name"] = "Other";
leftovers["Identifier"] = "other";
leftovers["name"] = "Other";
leftovers["identifier"] = "other";
for (const Documentation& doc : docs) {
leftovers["Classes"].push_back(generateJsonDocumentation(doc));
leftovers["classes"].push_back(generateJsonDocumentation(doc));
}
sortJson(leftovers["Classes"]);
sortJson(leftovers["classes"], "name");
json.push_back(leftovers);
sortJson(json);
sortJson(json, "name");
// I did not check the output of this for correctness ---abock
return json;
nlohmann::json result;
result["name"] = "Asset Types";
result["data"] = json;
return result;
}
} // namespace openspace

View File

@@ -84,4 +84,29 @@ std::string formatJsonNumber(double d) {
return std::to_string(d);
}
void sortJson(nlohmann::json& json, const std::string& key) {
std::sort(
json.begin(),
json.end(),
[&key](const nlohmann::json& lhs, const nlohmann::json& rhs) {
std::string lhsString = lhs[key];
std::string rhsString = rhs[key];
std::transform(
lhsString.begin(),
lhsString.end(),
lhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
std::transform(
rhsString.begin(),
rhsString.end(),
rhsString.begin(),
[](unsigned char c) { return std::tolower(c); }
);
return rhsString > lhsString;
}
);
}
} // namespace openspace