xref: /haiku/src/apps/haikudepot/build/scripts/jsonschema2cppmodel.py (revision ba1465cc865aa7bd71aa7ce2da65e25d68ae532f)
181dab213SAndrew Lindesay#!/usr/bin/python
281dab213SAndrew Lindesay
381dab213SAndrew Lindesay# =====================================
445f8be41SAndrew Lindesay# Copyright 2017-2023, Andrew Lindesay
581dab213SAndrew Lindesay# Distributed under the terms of the MIT License.
681dab213SAndrew Lindesay# =====================================
781dab213SAndrew Lindesay
881dab213SAndrew Lindesay# This simple tool will read a JSON schema and will then generate
981dab213SAndrew Lindesay# some model objects that can be used to hold the data-structure
1081dab213SAndrew Lindesay# in the C++ environment.
1181dab213SAndrew Lindesay
1281dab213SAndrew Lindesayimport json
1381dab213SAndrew Lindesayimport argparse
1481dab213SAndrew Lindesayimport os
1545f8be41SAndrew Lindesayimport hdsjsonschemacommon
1645f8be41SAndrew Lindesayimport ustache
1781dab213SAndrew Lindesay
1881dab213SAndrew Lindesay
1945f8be41SAndrew LindesayHEADER_TEMPLATE = """
2045f8be41SAndrew Lindesay/*
212174e23fSAndrew Lindesay * Generated Model Object for {{cppname}}
2245f8be41SAndrew Lindesay */
2381dab213SAndrew Lindesay
2445f8be41SAndrew Lindesay#ifndef GEN_JSON_SCHEMA_MODEL__{{cppnameupper}}_H
2545f8be41SAndrew Lindesay#define GEN_JSON_SCHEMA_MODEL__{{cppnameupper}}_H
2681dab213SAndrew Lindesay
27dc8d6e73SAndrew Lindesay#include <ObjectList.h>
289295c1f6SAndrew Lindesay#include <String.h>
2981dab213SAndrew Lindesay
3045f8be41SAndrew Lindesay{{#referencedclasscpptypes}}#include "{{.}}.h"
3145f8be41SAndrew Lindesay{{/referencedclasscpptypes}}
3281dab213SAndrew Lindesay
33*ba1465ccSAndrew Lindesay
3445f8be41SAndrew Lindesayclass {{cppname}} {
3581dab213SAndrew Lindesaypublic:
3645f8be41SAndrew Lindesay    {{cppname}}();
3745f8be41SAndrew Lindesay    virtual ~{{cppname}}();
38*ba1465ccSAndrew Lindesay
39*ba1465ccSAndrew Lindesay    void Reset();
4045f8be41SAndrew Lindesay{{#propertyarray}}{{#property.iscppscalartype}}
4145f8be41SAndrew Lindesay    {{property.cpptype}} {{property.cppname}}();
4245f8be41SAndrew Lindesay    void Set{{property.cppname}}({{property.cpptype}} value);
4345f8be41SAndrew Lindesay    void Set{{property.cppname}}Null();
4445f8be41SAndrew Lindesay    bool {{property.cppname}}IsNull();
4545f8be41SAndrew Lindesay{{/property.iscppscalartype}}{{#property.isarray}}
4645f8be41SAndrew Lindesay    void AddTo{{property.cppname}}({{property.items.cpptype}}* value);
4745f8be41SAndrew Lindesay    void Set{{property.cppname}}({{property.cpptype}}* value);
4845f8be41SAndrew Lindesay    int32 Count{{property.cppname}}();
4945f8be41SAndrew Lindesay    {{property.items.cpptype}}* {{property.cppname}}ItemAt(int32 index);
5045f8be41SAndrew Lindesay    bool {{property.cppname}}IsNull();
5145f8be41SAndrew Lindesay{{/property.isarray}}{{#property.iscppnonscalarnoncollectiontype}}
5245f8be41SAndrew Lindesay    {{property.cpptype}}* {{property.cppname}}();
5345f8be41SAndrew Lindesay    void Set{{property.cppname}}({{property.cpptype}}* value);
5445f8be41SAndrew Lindesay    void Set{{property.cppname}}Null();
5545f8be41SAndrew Lindesay    bool {{property.cppname}}IsNull();
5645f8be41SAndrew Lindesay{{/property.iscppnonscalarnoncollectiontype}}
5745f8be41SAndrew Lindesay{{/propertyarray}}
58*ba1465ccSAndrew Lindesay
59*ba1465ccSAndrew Lindesaypublic:
60*ba1465ccSAndrew Lindesay{{#propertyarray}}    static const uint16 k{{property.cppname}}Bitmask;
61*ba1465ccSAndrew Lindesay{{/propertyarray}}
62*ba1465ccSAndrew Lindesay
6345f8be41SAndrew Lindesayprivate:
64*ba1465ccSAndrew Lindesay    uint16 fHasValueBitmask;
65*ba1465ccSAndrew Lindesay{{#propertyarray}}    {{property.cpptype}}{{^property.iscppscalartype}}*{{/property.iscppscalartype}} {{property.cppmembername}};
6645f8be41SAndrew Lindesay{{/propertyarray}}
6745f8be41SAndrew Lindesay};
6845f8be41SAndrew Lindesay
6945f8be41SAndrew Lindesay#endif // GEN_JSON_SCHEMA_MODEL__{{cppnameupper}}_H
7045f8be41SAndrew Lindesay"""
7145f8be41SAndrew Lindesay
7245f8be41SAndrew LindesayIMPLEMENTATION_TEMPLATE = """
7345f8be41SAndrew Lindesay/*
742174e23fSAndrew Lindesay * Generated Model Object for {{cppname}}
7545f8be41SAndrew Lindesay */
7645f8be41SAndrew Lindesay
7745f8be41SAndrew Lindesay#include "{{cppname}}.h"
7881dab213SAndrew Lindesay
7981dab213SAndrew Lindesay
80*ba1465ccSAndrew Lindesay{{#propertyarray}}/*static*/ const uint16 {{cppname}}::k{{property.cppname}}Bitmask = {{cppbitmaskexpression}};
81*ba1465ccSAndrew Lindesay{{/propertyarray}}
82*ba1465ccSAndrew Lindesay
83*ba1465ccSAndrew Lindesay
8445f8be41SAndrew Lindesay{{cppname}}::{{cppname}}()
8545f8be41SAndrew Lindesay    :
86*ba1465ccSAndrew Lindesay    fHasValueBitmask(0),
87*ba1465ccSAndrew Lindesay{{#propertyarray}}    {{property.cppmembername}}({{property.cppdefaultvalue}}){{^islast}},{{/islast}}
8845f8be41SAndrew Lindesay{{/propertyarray}}{
8945f8be41SAndrew Lindesay}
9081dab213SAndrew Lindesay
9181dab213SAndrew Lindesay
9245f8be41SAndrew Lindesay{{cppname}}::~{{cppname}}()
9345f8be41SAndrew Lindesay{
94*ba1465ccSAndrew Lindesay    Reset();
95*ba1465ccSAndrew Lindesay}
96*ba1465ccSAndrew Lindesay
97*ba1465ccSAndrew Lindesay
98*ba1465ccSAndrew Lindesayvoid
99*ba1465ccSAndrew Lindesay{{cppname}}::Reset()
100*ba1465ccSAndrew Lindesay{
101*ba1465ccSAndrew Lindesay{{#propertyarray}}{{#property.isstring}}    delete {{property.cppmembername}};
102*ba1465ccSAndrew Lindesay{{/property.isstring}}{{#property.isobject}}    delete {{property.cppmembername}};
103*ba1465ccSAndrew Lindesay{{/property.isobject}}{{#property.isarray}}
104*ba1465ccSAndrew Lindesay    if ({{property.cppmembername}} != NULL) {
10545f8be41SAndrew Lindesay        for (int i = {{property.cppmembername}}->CountItems() - 1; i >= 0; i--)
10645f8be41SAndrew Lindesay            delete {{property.cppmembername}}->ItemAt(i);
10745f8be41SAndrew Lindesay        delete {{property.cppmembername}};
10845f8be41SAndrew Lindesay    }
109*ba1465ccSAndrew Lindesay{{/property.isarray}}    {{property.cppmembername}} = {{property.cppdefaultvalue}};
110*ba1465ccSAndrew Lindesay{{/propertyarray}}
111*ba1465ccSAndrew Lindesay    fHasValueBitmask = 0;
112*ba1465ccSAndrew Lindesay}
11381dab213SAndrew Lindesay
11445f8be41SAndrew Lindesay{{#propertyarray}}{{#property.iscppscalartype}}{{property.cpptype}}
11545f8be41SAndrew Lindesay{{cppobjectname}}::{{property.cppname}}()
11645f8be41SAndrew Lindesay{
117*ba1465ccSAndrew Lindesay    return {{property.cppmembername}};
11845f8be41SAndrew Lindesay}
11981dab213SAndrew Lindesay
12081dab213SAndrew Lindesay
12145f8be41SAndrew Lindesayvoid
12245f8be41SAndrew Lindesay{{cppobjectname}}::Set{{property.cppname}}({{property.cpptype}} value)
12345f8be41SAndrew Lindesay{
124*ba1465ccSAndrew Lindesay    fHasValueBitmask |= k{{property.cppname}}Bitmask;
125*ba1465ccSAndrew Lindesay    {{property.cppmembername}} = value;
12645f8be41SAndrew Lindesay}
12781dab213SAndrew Lindesay
12881dab213SAndrew Lindesay
12945f8be41SAndrew Lindesayvoid
13045f8be41SAndrew Lindesay{{cppobjectname}}::Set{{property.cppname}}Null()
13145f8be41SAndrew Lindesay{
132*ba1465ccSAndrew Lindesay    fHasValueBitmask &= ~k{{property.cppname}}Bitmask;
133*ba1465ccSAndrew Lindesay    {{property.cppmembername}} = {{property.cppdefaultvalue}};
13445f8be41SAndrew Lindesay}
13581dab213SAndrew Lindesay
13681dab213SAndrew Lindesay
13745f8be41SAndrew Lindesaybool
13845f8be41SAndrew Lindesay{{cppobjectname}}::{{property.cppname}}IsNull()
13945f8be41SAndrew Lindesay{
140*ba1465ccSAndrew Lindesay    return 0 == (fHasValueBitmask & k{{property.cppname}}Bitmask);
14145f8be41SAndrew Lindesay}
14281dab213SAndrew Lindesay
14345f8be41SAndrew Lindesay{{/property.iscppscalartype}}{{#property.isarray}}void
14445f8be41SAndrew Lindesay{{cppobjectname}}::AddTo{{property.cppname}}({{property.items.cpptype}}* value)
14545f8be41SAndrew Lindesay{
14645f8be41SAndrew Lindesay    if ({{property.cppmembername}} == NULL)
14745f8be41SAndrew Lindesay        {{property.cppmembername}} = new {{property.cpptype}}();
14845f8be41SAndrew Lindesay    {{property.cppmembername}}->AddItem(value);
14945f8be41SAndrew Lindesay}
15081dab213SAndrew Lindesay
15181dab213SAndrew Lindesay
15245f8be41SAndrew Lindesayvoid
15345f8be41SAndrew Lindesay{{cppobjectname}}::Set{{property.cppname}}({{property.cpptype}}* value)
15445f8be41SAndrew Lindesay{
15545f8be41SAndrew Lindesay    if ({{property.cppmembername}} != NULL) {
15645f8be41SAndrew Lindesay        delete {{property.cppmembername}};
15745f8be41SAndrew Lindesay    }
15845f8be41SAndrew Lindesay    {{property.cppmembername}} = value;
15945f8be41SAndrew Lindesay}
16081dab213SAndrew Lindesay
16145f8be41SAndrew Lindesay
16245f8be41SAndrew Lindesayint32
16345f8be41SAndrew Lindesay{{cppobjectname}}::Count{{property.cppname}}()
16445f8be41SAndrew Lindesay{
16545f8be41SAndrew Lindesay    if ({{property.cppmembername}} == NULL)
16645f8be41SAndrew Lindesay        return 0;
16745f8be41SAndrew Lindesay    return {{property.cppmembername}}->CountItems();
16845f8be41SAndrew Lindesay}
16945f8be41SAndrew Lindesay
17045f8be41SAndrew Lindesay
17145f8be41SAndrew Lindesay{{property.items.cpptype}}*
17245f8be41SAndrew Lindesay{{cppobjectname}}::{{property.cppname}}ItemAt(int32 index)
17345f8be41SAndrew Lindesay{
17445f8be41SAndrew Lindesay    return {{property.cppmembername}}->ItemAt(index);
17545f8be41SAndrew Lindesay}
17645f8be41SAndrew Lindesay
17745f8be41SAndrew Lindesay
17845f8be41SAndrew Lindesaybool
17945f8be41SAndrew Lindesay{{cppobjectname}}::{{property.cppname}}IsNull()
18045f8be41SAndrew Lindesay{
18145f8be41SAndrew Lindesay    return {{property.cppmembername}} == NULL;
18245f8be41SAndrew Lindesay}
18345f8be41SAndrew Lindesay
18445f8be41SAndrew Lindesay{{/property.isarray}}{{#property.iscppnonscalarnoncollectiontype}}{{property.cpptype}}*
18545f8be41SAndrew Lindesay{{cppobjectname}}::{{property.cppname}}()
18645f8be41SAndrew Lindesay{
18745f8be41SAndrew Lindesay    return {{property.cppmembername}};
18845f8be41SAndrew Lindesay}
18945f8be41SAndrew Lindesay
19045f8be41SAndrew Lindesay
19145f8be41SAndrew Lindesayvoid
19245f8be41SAndrew Lindesay{{cppobjectname}}::Set{{property.cppname}}({{property.cpptype}}* value)
19345f8be41SAndrew Lindesay{
19445f8be41SAndrew Lindesay    {{property.cppmembername}} = value;
19545f8be41SAndrew Lindesay}
19645f8be41SAndrew Lindesay
19745f8be41SAndrew Lindesay
19845f8be41SAndrew Lindesayvoid
19945f8be41SAndrew Lindesay{{cppobjectname}}::Set{{property.cppname}}Null()
20045f8be41SAndrew Lindesay{
20145f8be41SAndrew Lindesay    if (!{{property.cppname}}IsNull()) {
20245f8be41SAndrew Lindesay        delete {{property.cppmembername}};
20345f8be41SAndrew Lindesay        {{property.cppmembername}} = NULL;
20445f8be41SAndrew Lindesay    }
20545f8be41SAndrew Lindesay}
20645f8be41SAndrew Lindesay
20745f8be41SAndrew Lindesay
20845f8be41SAndrew Lindesaybool
20945f8be41SAndrew Lindesay{{cppobjectname}}::{{property.cppname}}IsNull()
21045f8be41SAndrew Lindesay{
21145f8be41SAndrew Lindesay    return {{property.cppmembername}} == NULL;
21245f8be41SAndrew Lindesay}
21345f8be41SAndrew Lindesay
21445f8be41SAndrew Lindesay{{/property.iscppnonscalarnoncollectiontype}}
21545f8be41SAndrew Lindesay{{/propertyarray}}
21645f8be41SAndrew Lindesay"""
21745f8be41SAndrew Lindesay
21845f8be41SAndrew Lindesay
21945f8be41SAndrew Lindesaydef write_models_for_schema(schema: dict[str, any], output_directory: str) -> None:
22045f8be41SAndrew Lindesay
22145f8be41SAndrew Lindesay    def write_model_object(obj: dict[str, any]) -> None:
22245f8be41SAndrew Lindesay        cpp_name = obj["cppname"]
22345f8be41SAndrew Lindesay        cpp_header_filename = os.path.join(output_directory, cpp_name + '.h')
22445f8be41SAndrew Lindesay        cpp_implementation_filename = os.path.join(output_directory, cpp_name + '.cpp')
22545f8be41SAndrew Lindesay
22645f8be41SAndrew Lindesay        with open(cpp_header_filename, 'w') as cpp_h_file:
22745f8be41SAndrew Lindesay            cpp_h_file.write(ustache.render(
22845f8be41SAndrew Lindesay                HEADER_TEMPLATE,
22945f8be41SAndrew Lindesay                obj,
23045f8be41SAndrew Lindesay                escape= lambda x: x))
23145f8be41SAndrew Lindesay
23245f8be41SAndrew Lindesay        with open(cpp_implementation_filename, 'w') as cpp_i_file:
23345f8be41SAndrew Lindesay            cpp_i_file.write(ustache.render(
23445f8be41SAndrew Lindesay                IMPLEMENTATION_TEMPLATE,
23545f8be41SAndrew Lindesay                obj,
23645f8be41SAndrew Lindesay                escape= lambda x: x))
23745f8be41SAndrew Lindesay
2382174e23fSAndrew Lindesay    for obj in hdsjsonschemacommon.collect_all_objects(schema):
23945f8be41SAndrew Lindesay        write_model_object(obj)
24045f8be41SAndrew Lindesay
24181dab213SAndrew Lindesay
24281dab213SAndrew Lindesaydef main():
24345f8be41SAndrew Lindesay    parser = argparse.ArgumentParser(
24445f8be41SAndrew Lindesay        description='Convert JSON schema to Haiku C++ Models')
24545f8be41SAndrew Lindesay    parser.add_argument(
24645f8be41SAndrew Lindesay        '-i', '--inputfile',
24745f8be41SAndrew Lindesay        required=True,
24845f8be41SAndrew Lindesay        help='The input filename containing the JSON schema')
24945f8be41SAndrew Lindesay    parser.add_argument(
25045f8be41SAndrew Lindesay        '--outputdirectory',
25145f8be41SAndrew Lindesay        help='The output directory where the C++ files should be written')
25281dab213SAndrew Lindesay
25381dab213SAndrew Lindesay    args = parser.parse_args()
25481dab213SAndrew Lindesay
25545f8be41SAndrew Lindesay    output_directory = args.outputdirectory
25681dab213SAndrew Lindesay
25745f8be41SAndrew Lindesay    if not output_directory:
25845f8be41SAndrew Lindesay        output_directory = '.'
25981dab213SAndrew Lindesay
26081dab213SAndrew Lindesay    with open(args.inputfile) as inputfile:
26181dab213SAndrew Lindesay        schema = json.load(inputfile)
26245f8be41SAndrew Lindesay        hdsjsonschemacommon.augment_schema(schema)
26345f8be41SAndrew Lindesay        write_models_for_schema(schema, output_directory)
26445f8be41SAndrew Lindesay
26581dab213SAndrew Lindesay
26681dab213SAndrew Lindesayif __name__ == "__main__":
26781dab213SAndrew Lindesay    main()
26881dab213SAndrew Lindesay
269