{"id":19225452,"url":"https://github.com/quotient-im/gtad","last_synced_at":"2025-06-14T09:36:10.138Z","repository":{"id":61510126,"uuid":"75084211","full_name":"quotient-im/gtad","owner":"quotient-im","description":"Generate Things from API Descriptions","archived":false,"fork":false,"pushed_at":"2024-08-26T11:15:23.000Z","size":798,"stargazers_count":12,"open_issues_count":8,"forks_count":2,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-08-26T13:39:25.621Z","etag":null,"topics":["code-generation","openapi","openapi-specification","rest-api","swagger"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/quotient-im.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-11-29T13:31:05.000Z","updated_at":"2024-08-26T11:15:26.000Z","dependencies_parsed_at":"2024-04-13T01:43:13.156Z","dependency_job_id":"d40310ef-ea0a-4913-bde4-1ea47b540bff","html_url":"https://github.com/quotient-im/gtad","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quotient-im%2Fgtad","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quotient-im%2Fgtad/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quotient-im%2Fgtad/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/quotient-im%2Fgtad/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/quotient-im","download_url":"https://codeload.github.com/quotient-im/gtad/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223842093,"owners_count":17212323,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["code-generation","openapi","openapi-specification","rest-api","swagger"],"created_at":"2024-11-09T15:15:08.840Z","updated_at":"2024-11-09T15:15:09.389Z","avatar_url":"https://github.com/quotient-im.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GTAD\n\n[![license](https://img.shields.io/github/license/KitsuneRal/gtad.svg)](https://github.com/KitsuneRal/gtad/blob/master/LICENSE)\n![status](https://img.shields.io/badge/status-beta-yellow.svg)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)\n\nGTAD (Generate Things from an API Description) is a work-in-progress \ngenerator of code from a Swagger/OpenAPI specification. Initially made to \ngenerate marshalling/unmarshalling C++ code for\n[Matrix CS API](https://matrix.org/docs/spec/client_server/unstable.html),\nit can be extended to support other API descriptions (possibly even spreading\nto other API description languages, such as RAML) and other programming\nlanguages with static type checking.\n\nA brief introduction to the topic of API description languages (ADLs) can be\nfound in [the talk at Qt World Summit 2017](https://youtu.be/W5TmRozH-rg) that\nalso announces the GTAD project.\n\n## Contacts\nMatrix room: [#gtad:matrix.org](https://matrix.to/#/#gtad:matrix.org).\n\nYou can also file issues at\n[the project's issue tracker](https://github.com/KitsuneRal/gtad/issues).\n\n## Setting up and building\nThe source code is hosted at [GitHub](https://github.com/KitsuneRal/gtad/). Tags\nstarting with `v` represent released versions; `rc` mark release candidates.\nDo remember to use `--recursive` or update submodules after checking out -\nthe project has external dependencies taken in as submodules (this may change\nin the future).\n\n### Pre-requisites\n- a recent Linux, Windows or macOS system\n- a Git client to check out this repo\n- Qt 6 (either Open Source or Commercial)\n- CMake 3.20 or newer (from your package management system or\n  [the official website](https://cmake.org/download/))\n- a C++ toolchain with solid C++20 and at least some C++23 support (ranges, in particular), that is:\n  GCC 13 (Windows, Linux, OSX), Clang 16 (Linux), Xcode 15 (macOS 13),\n  Visual C++ 19.30 (aka VS 2022 17.0), or newer\n- any build system that works with CMake and/or qmake should be fine:\n  GNU Make, ninja (any platform), NMake, jom (Windows) are known to work.\n- for the actual invocation - clang-format in your PATH or CLANG_FORMAT variable\n  having a full path to clang-format.\n\n#### Linux\nJust install things from the list above using your preferred package manager.\nGTAD only uses a tiny subset of Qt Base so you can install as little of Qt as\npossible.\n\n#### OS X\n`brew install qt` should get you a recent Qt. You may need to tell CMake\nabout the path to Qt by passing `-DCMAKE_PREFIX_PATH=\u003cwhere-Qt-installed\u003e`.\n\n#### Windows\n1. Install Qt and CMake.\n1. The commands in further sections imply that cmake is in your PATH - otherwise\n   you have to prepend those commands with actual paths. As an option, it's a \n   good idea to run a `qtenv2.bat` script that can be found in\n   `C:\\Qt\\\u003cQt version\u003e\\\u003ctoolchain\u003e\\bin` (assuming you installed Qt to `C:\\Qt`);\n   the only thing it does is adding necessary paths to PATH. You might not want\n   to run that script on system startup but it's very handy to setup\n   the environment before building. Setting `CMAKE_PREFIX_PATH` in the same way\n   as for OS X (see above) is fine too.\n\n### Building\nIn the root directory of the project sources:\n```\nmkdir build_dir\ncd build_dir\ncmake .. # Pass -DCMAKE_PREFIX_PATH and -DCMAKE_INSTALL_PREFIX here if needed\ncmake --build . --target all\n```\nThis will produce a gtad binary in `build_dir` inside your project sources.\nInstalling is not generally supported yet; `cmake --build . --target install`\ninstalls a single executable with no dependencies and/or documentation.\n\n## Usage\n\nGTAD uses 3 inputs to generate \"things\":\n1. Swagger/OpenAPI definition files, further referred to as OpenAPI files or\n   OpenAPI definitions. Only\n   [OpenAPI 2](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md)\n   is supported for now (version 3 is in\n   [the roadmap](https://github.com/KitsuneRal/gtad/projects/1#column-526169)).\n   Each file is treated as a separate source. Notably, the referenced\n   (via `$ref`) files are parsed independently from the referring ones;\n   the generated code is supposed to import the files produced from\n   the referenced OpenAPI definitions.\n2. A configuration file in YAML. One GTAD invocation always uses one\n   configuration file (but you can invoke GTAD separately for different OpenAPI\n   files). The format of this file is described in detail below.\n3. Source code template files. As of now, GTAD uses\n   [Kainjow's Mustache implementation](https://github.com/kainjow/Mustache) for\n   templating. GTAD exports the model for the API as\n   a Mustache structure; this is covered in the respective section below.\n\nA good example of GTAD usage can be found in\n[libQuotient](https://github.com/quotient-im/libQuotient/) that has\nits network request classes generated from OpenAPI definitions of\n[Matrix CS API](https://matrix.org/docs/spec/client_server/unstable.html).\nThe CMakeLists.txt has a GTAD invocation line, using\n[gtad.yaml](https://github.com/quotient-im/libQuotient/blob/master/gtad/gtad.yaml)\nfor the configuration file and a few Mustache templates for code generation\nnext to it. See also notes in that project's\n[CONTRIBUTING.md](https://github.com/quotient-im/libQuotient/blob/master/CONTRIBUTING.md)\nand\n[CMakeLists.txt](https://github.com/quotient-im/libQuotient/blob/master/CMakeLists.txt)\nfor an idea how to integrate GTAD in your project.\n\n### Invocation\n\nGTAD is a command-line application; assuming that the `gtad` binary is in your\n`PATH`, the invocation line looks as follows:\n```\ngtad --config \u003cconfigfile\u003e --out \u003coutdir\u003e \u003cfiles/dirs...\u003e\n```\nThe options are:\n- `\u003cconfigfile\u003e` - the path to GTAD configuration file (see the next section)\n- `\u003coutdir\u003e` - the (top-level) directory where the generated files (possibly\n  a tree of them) will be put. Must exist before runnning GTAD.\n- `\u003cfiles/dirs...\u003e` - a list of OpenAPI files or directories with those files\n  to process. A hyphen appended to the filename means that the file must be \n  skipped (allows to select a directory with files and then explicitly disable\n  some files in it).\n\nSince version 0.9 GTAD uses clang-format at the last stage of files generation\nto format the emitted files. For that to work, a binary that can be called\nas `clang-format` (that is, `clang-format` for POSIX systems and\n`clang-format.exe` for Windows) should reside in `PATH`. Alternatively, you can\npass the full path in the `CLANG_FORMAT` environment variable. While the target\nformat is normally specified in a `.clang-format` file, you can override that\nby passing Clang-format command-line options in `CLANG_FORMAT_ARGS` - notably,\nif you prefer to skip formatting for whatever reason, you can set\n`CLANG_FORMAT_ARGS=\"-n\"` (dry-run mode) before invoking GTAD.\n\n#### Dealing with referenced files\n\nIf a processed OpenAPI file has a `$ref` value referring to relative paths,\nthe referred file will be added to the processing list (even if they were\ndisabled in the command line as described above). The respective relative path\nwill be created in the output directory, so if an OpenAPI file has\n`\"$ref\": \"definitions/events.yml\"`, the `\u003coutdir\u003e/definitions` directory will\nbe created and the file(s) generated from `definitions/events.yml` will be put\nin there. Note that if `definitions/events.yml` has `\"$ref\": events/base.yml`,\nthe `events` directory will be searched under input `definitions` directory, and\na respective `\u003coutdir\u003e/definitions/events` directory will be made for output\nfiles from `base.yml` processing.\n\nSince version 0.11, GTAD also supports local `$ref` objects (those with `$ref` starting with `#`).\nSchemas loaded from the local `$ref` will be emitted as a part of the current model, rather than\nput in their own files.\n\n### GTAD configuration file\n\nGTAD uses a configuration file written in YAML to customise type mapping and\nfiles generation. The configuration consists of 2 main parts: `analyzer`\n(Analyzer configuration) and `mustache` (Printer configuration). As mentioned\nabove, libQuotient has the (working in production) example of\na configuration file.\n\n#### Analyzer configuration\n\nAnalyzer configuration is a YAML object that includes the following parts.\n\n##### `subst`\nA regex-to-pattern map of substitutions that should be applied before any\nprocessing takes place - for each `old: new` entry the effect will be the same\nas if a regex replacement (`s/old/new/`) were applied to the entire input.\nBe careful with such substitutions, as they ignore YAML/JSON structure of\nthe API description; a careless regex can easily render the input invalid.\n\n##### `identifiers`\n(Since GTAD 0.6) This is a map of more fine-tuned substitutions compared to\n`subst`, only applied to _names_ (identifiers) encountered in OpenAPI. For now\nit's only applied to names of call parameters, schemas and schema properties\nbut not, notably, to call names (operationIds).\n\nThere are two ways to specify a match. By default, the names are matched\nsensitive to case and literally; but if the match string starts with a `/`\nthe rest of the string until the trailing optional `/` becomes a regular\nexpression as described at https://en.cppreference.com/w/cpp/regex/ecmascript.\nWhen using the regular expression for matching, the substitution string can\ninclude `$1`,`$2`,... to reference the submatches; or `$\u0026` to reference\nthe entire match. Except from the first and the last position, `/` has\nno special meaning and should not be escaped.\n\nOne of the main cases for `identifiers` is to change names that clash\nwith reserved words of the target language (`unsigned` in the example below)\nor otherwise undesirable as field/parameter names. If you add, e.g.,\n`unsigned: unsignedData` to the `identifiers` section, GTAD will transform\nall target parameter names `unsigned` to `unsignedData`, unbreaking C++ code\nthat otherwise would be invalid. The Mustache configuration will have both\nthe original (`{{baseName}}`) and the transformed (`{{paramName}}` or\n`{{nameCamelCase}}`) names of those parameters so that you can still use\nthe original name for JSON key names in actual API payloads and\na transformed one to name C++ identifiers in your template files.\n\nSince GTAD 0.7 you can use the scope (schema or call name; see below for\nthe caveat on the call name syntax) to match specific occurence(s) of\nthe identifier. The scope name is matched in the original form as it appears\nin the API description file but is not represented in the substituting string\nin any way; it cannot be rewritten. The separating character is `/` (unescaped, as mentioned).\nFor calls, you should use the name provided in the `operationId` field\nfollowed by either `\u003e` for identifiers in the request or `\u003c` for those\nin the response. If you need to cover both directions, you're likely also\ncovering several calls using a regex; just put a full stop (`.`)\ninstead of the direction character.\n\nScope matching is especially useful to adjust the parameter name for `patternProperties` and\n`additionalProperties` (see further in this document) in different schemas and the \"packed\" response\nbody name (by default it's always `data`) in different calls. A \"packed\" body is a case when\nthe entire JSON in the request or response body is treated as a single piece (parameter or\nreturned value, respectively). In the opposite, \"unpacked\" case the top-level JSON object in\nthe request body or response body is \"destructured\" to several parameters/accessors.\n\nAlso since GTAD 0.7 you can skip the entire field by renaming it to an empty\nstring. This is useful to prune deprecated fields from your generated code\nwithout touching the original API description. To protect you from shooting\nyourself in the foot GTAD will error if an attempt is made to remove a field \nthat has `required: true` in the API description.\n\nExample (the first line works in GTAD 0.6, the rest since GTAD 0.7): \n```yaml\ndefault: isDefault                                # 1\nAuthenticationData/additionalProperties: authInfo # 2\n/^requestTokenTo.*\u003c/data/: response               # 3\n/requestOpenIdToken\u003c/(.*)/: token$1               # 4\nsetAccountData\u003e/additionalProperties: accountData # 5\ngetProtocols\u003c/data: protocols                     # 6\nlogin\u003e/medium: \"\" # The quotes are mandatory here # 7\n```\nThis will:\n1. All parameters named `default` in the source API will be named `isDefault`\n   in the generated code.\n2. Rename the `additionalProperties` field of `AuthenticationData`\n   schema to `authInfo`. The schema name will be kept intact, only\n   the identifier will be renamed.\n3. For any call with the name starting with `requestTokenTo`, rename the `data`\n   parameter (likely, but not necessarily, representing the \"packed\" response\n   body) occuring in the call's response (`\u003c`) to `response`. The call name\n   itself is not changed.\n4. For a call named `requestOpenIdToken`, prepend every parameter in its\n   response with `token`. This line can be abbreviated to\n   `/requestOpenIdToken\u003c/: token`; this is not recommended though, as it relies\n   quite heavily on the specific way GTAD makes a replacement and may break\n   once this logic changes.\n5. Rename the `additionalProperties` field occuring in the top level of\n   the `setAccountData` call's request body to `accountData`.\n6. Rename the `data` field (likely a \"packed\" response body) in\n   the `getProtocols` call's response body to `protocols`.\n7. Completely remove the `medium` parameter from the `login` request definition,\n   as long as this parameter is not marked with `required: true` in the API\n   description file. \n\n##### `types`\nThis is the biggest and the most important part of the analyzer configuration,\ndefining which OpenAPI types and data structures become which target language\ntypes and structures in generated files. Before moving on further I strongly\nrecommend to open the types map in libQuotient's `gtad.yaml` next to this\nfile: it's one of those cases when an example can better explain the matter\nthan a thousand words.\n\nThis section is a list (YAML array) of entries; each entry is either\nof the following:\n```yaml\n- \u003cswaggerType\u003e: \u003ctargetTypeSpec\u003e\n```\nor\n```yaml\n- \u003cswaggerType\u003e:\n  - \u003cswaggerFormat\u003e: \u003ctargetTypeSpec\u003e\n  - /\u003cswaggerFormatRegEx\u003e/:\n      \u003ctargetTypeSpec\u003e\n  - //: \u003ctargetTypeSpec\u003e # default, if the format doesn't mach anything above\n```\nor\n```yaml\n- +set: { \u003cattributes\u003e }\n  +on: [ \u003ctypesMap\u003e ]\n```\nIn the above,\n- `\u003cswaggerType\u003e` and `\u003cswaggerFormat\u003e`/`\u003cswaggerFormatRegEx\u003e` are matched\n  against _type_ and _format_ in the API description (see below on extensions\n  to OpenAPI _types_ and _formats_). If the _format_ key starts with a `/`\n  (forward slash) it is treated as a regular expression (the trailing slash is\n  optional and is not processed - if you need it to be the last character of\n  the regex, just add one more `/`), otherwise it's used as a literal\n  case-sensitive string.\n  \n- `\u003ctargetTypeSpec\u003e` is either the target type literal string (such as\n  `double`) or, in turn, a YAML object:\n  ```yaml\n      type: \u003ctarget type literal\u003e # mandatory except for 'schema' and mappings in 'references'\n      imports: \u003cfilename\u003e or [ \u003cfilenames...\u003e ] # optional\n      ... # key-value pairs for custom type attributes, optional\n  ```\n  Each `\u003ctargetTypeSpec\u003e` (except those in `schema`, see below)\n  must unambiguously specify the target type to be used - either as a string\n  (`bool`) or as an object with `type` property (`{ type: bool }`). For\n  the purpose of proper rendering you will likely need to pass (and use in\n  your Mustache templates) additional information about the mapped type -\n  e.g., whether the type is copyable, whether it should be wrapped up in\n  another type in case a parameter is optional, or which import - for C/C++\n  it's a file for `#include` - should be added. To address that, GTAD has\n  a concept of _type attributes_: every type can have an arbitrary number of\n  \"attributes\" with arbitrary (except `type`) names, modeled as string-to-string\n  or string-to-list mappings. `imports` is an example of a string-to-list\n  mapping.\n  \n  At the moment GTAD special-cases `imports`: in addition to just passing this\n  attribute along with the type name, it adds its contents to a \"global\" (per\n  input file) deduplicated set, to simplify generation of import/include\n  blocks. Since some of imports come from `$ref` objects in API descriptions\n  (see below), GTAD also translates the original `$ref` path to a form\n  suitable to import the respective data structure in the target language.\n  Before GTAD 0.8, that was really hardcoded to C/C++; GTAD used the first\n  extension in a given (`data` or `api`) subsection of `templates` to append\n  to the relative path and added quotes to paths that didn't have it.\n  GTAD 0.8 introduced a concept of _import renderers_, Mustache templates\n  that allow some basic configuration of the import transformation. This is\n  discussed in a dedicated section below.\n\n- `+set/+on` statement allows you to apply type attributes to several mappings\n  at once:\n  ```yaml\n  - +set: { avoidCopy: } # Add 'avoidCopy' attribute...\n    +on: # ...to anything matched by the list below\n    - object: # ...\n    - string: string\n    - schema: # ...\n  ```\nNote that you should only specify any particular _type_/_format_ combination\nno more than once. The lookup will stop on the first match, even if it only\nspecifies attributes, without a type.\n\n###### Supported types and formats\nAs mentioned above, `swaggerType` and `swaggerFormat`/`swaggerFormatRegEx` are matched against\n_type_ and _format_ specified in API description.\n[OpenAPI 2](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#user-content-data-types)\nand [OpenAPI 3](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#data-types)\ndefine standard _types_ and _formats_; on top of these you can use the following non-standard\n_types_/_formats_ in the GTAD configuration file (but _not_ in the API descriptions):\n\n- \"_formats_\" under _type_ `array` are used to match arrays with elements\n  of a certain element type. This way you can, e.g., special case an array\n  of strings as `QStringList` and still use `QVector\u003c\u003e` for arrays of all other\n  types (including objects and other arrays). To render parameterised types\n  GTAD assumes that strings under the `type` key in `\u003ctargetTypeSpec\u003e` are\n  themselves Mustache templates (in Mustache parlance - _partials_) and passes\n  the parameter type as value `{{1}}`. Therefore, to use `QVector\u003c\u003e` for\n  arrays you should write something like this:\n  ```yaml\n  - array:\n      type: \"QVector\u003c{{1}}\u003e\"\n      imports: \u003cQVector\u003e\n  ```\n  or, if you prefer the \"flow\" style of YAML,\n  ```yaml\n  - array: { type: \"QVector\u003c{{1}}\u003e\", imports: \u003cQVector\u003e }\n  ```\n\n- `schema`: this matches all types defined within the API definition as _schema_ structures,\n  as long as these structures are not _trivial_. (A trivial schema is a wrapper around another type,\n  such as `string` or a singular `$ref`, without additional parameter definitions; technically,\n  it can be represented as a data structure that derives from a single base type, with fields added.\n  Such a schema will be inlined (=substituted with that type) on every possible occasion; normally\n  you should never see it in generated code.)\n  \n  The list of \"_formats_\" inside `schema` allows to specify types, for which\n  special target types/attributes should be used. Same as for other types,\n  _formats_ under `schema` are either regexes if they start with `/`\n  or literal case-sensitive strings otherwise. _Formats_ match:\n  - the `title` attribute provided within the schema definition of API file;\n  - failing that, schema's title as calculated after resolving `$ref`\n    attributes (note that some `$ref`'s can be intercepted, as described\n    in the next bullet)\n  - (since GTAD 0.7) for top-level request/response schemas _format_\n    also matches the operation's `operationId` with a `\u003e` appended\n    for requests, `\u003c` for responses (in the same vein as for `identifiers`\n    entries) - e.g., `getTurnServers\u003c` matches the top-level schema for\n    the response body of `getTurnServers`.\n\n  In case of schemas, `\u003ctargetTypeSpec\u003e` may omit `type` entirely and only supply additional\n  attributes that will be added to the Mustache context at each usage of the given type, while\n  the original schema is used to define the type. In GTAD 0.11, the `title` attribute has\n  a special meaning in this context: it preserves the original type definition but overrides\n  the type name (as if the respective `title` were provided in the API description instead). In\n  versions 0.7 through 0.10.x, the same effect could be achieved by supplying `_title` attribute\n  under `$ref`; this didn't allow to rename schemas not involved in reference objects, hence\n  the new mechanism.\n\n- `$ref` - this is a historical key supported by GTAD versions from 0.6 to 0.10.x; it was moved out\n  to its own `references` section under `analyzer` in GTAD 0.11, see below.\n    \n- _type_ `object`: this is an entry (without _formats_ underneath) that\n  describes the target type to be used when GTAD could not find any schema\n  for it and the context implies that there are no restrictions on the type\n  (but some data structure is still needed). Notably, this target type is used\n  when an input parameter for an API call is described as `schema` without\n  any attributes or with a sole `type: object` attribute; this normally means\n  that a user can supply _anything_. Either a generic type (`std::any` in\n  C++17 or `void*` in C) or a generic JSON object such as Qt's `QJsonObject`\n  (as long as the API is based on JSON structures) can be used for this purpose.\n\n- `map`: this corresponds to OpenAPI's `patternProperties` (since GTAD 0.11) and\n  `additionalProperties`. In terms of actual API these define an open list of properties without\n  saying which names those properties must have: the API description file does not define property\n  names, but only the mapped type. Similar to arrays, GTAD matches _formats_ under this _type_\n  against the type defined inside `patternProperties`/`additionalProperties` (type of property\n  values). A typical translation of that in static-typed languages involves a map from strings\n  to structures; e.g. the current libQuotient uses `QHash\u003cQString, {{1}}\u003e` (`QHash\u003c{{1}}, {{2}}`\n  since GTAD 0.11, see the next paragraph) as the default data structure for `map` when the mapped\n  data type is defined, `QVariantHash` for a generic map with no specific type, and as a special\n  case, `std::unordered_map\u003cQString, {{1}}\u003e` (`std::unordered_map\u003c{{1}}, {{2}}\u003e` since GTAD 0.11,\n  see the next paragraph) when the contained schema's title is `RoomState` because that type is\n  uncopyable and therefore cannot be stored in a `QHash`.\n\n  With support for `patternProperties` added in GTAD 0.11, it also became possible to specify\n  the mapping for the property name type, thanks to an OpenAPI extension used in Matrix.org\n  API definitions. The extension is a key-value pair with the key named `x-pattern-format` added\n  for the given pattern, next to the definition of the property value type, e.g.:\n  ```yaml\n  patternProperties:\n    \"^@\":\n      type: object\n      x-pattern-format: mx-user-id\n      additionalProperties:\n        type: number\n  ```\n  By default, the property name type is `string`, mapped to the target type according to usual\n  rules. `x-pattern-format` allows to override that. To map `mx-user-id` to some other type than\n  whatever `string` is mapped to, just add an `mx-user-id` entry to the list of formats under\n  `string` type. E.g., the following configuration in `gtad.yaml`:\n  ```yaml\n  types:\n    number: float\n    string:\n    - mx-user-id: UserId\n    # ...\n    map:\n    - /.+/: \"QHash\u003c{{1}}, {{2}}\u003e\"\n  ```\n  would cause GTAD to translate the above `patternProperties` block into an additional `data` field\n  with the type `QHash\u003cUserId, float\u003e`.\n\n  Be mindful that GTAD pre-0.11 only used one parameter for target types in `map` and would ignore\n  `patternProperties` entirely, only processing `additionalProperties`.\n\n- `variant` (supported from GTAD 0.6): this is a case of variant types or\n  multitypes. Similar to `map` and others, you can override certain type\n  combinations and use a dedicated type for them. The _format_ pattern under\n  `variant` should list the types separated by `,` (comma) in _exactly\n  the same order as in the API description_ (`string,object` and\n  `object,string` are distinct sequences). Also, beware that `null` is a\n  reserved keyword in JSON/YAML, so OpenAPI's `null` type should be escaped\n  with quotes (e.g., `\"string,null\"`).\n  \n  The list of types (for cases when the target type delimits the stored types,\n  such `std::variant\u003c\u003e` from C++17) is stored in `{{types}}` variable:\n  e.g. mapping to C++17 `std::variant\u003c\u003e` might look like:\n  ```yaml\n  variant:\n    type: std::variant\u003c{{#types}}{{_}}{{#_join}}, {{/_join}}{{/types}}\u003e\n    imports: \u003cvariant\u003e\n  ```\n\n##### Advanced type mapping configuration\n\nIn case when an element type of an array or a property map is in turn\na container (an array, a map/`additionalProperties` or a variant) _and_ it\ndoes not have a name, the _format_ can be specified as follows (no nesting,\n`string[][]` is not supported):\n- for arrays: `\u003celementType\u003e[]`;\n- for maps aka `additionalProperties`: `string-\u003e\u003celementType\u003e`;\n- for variants: `\u003celementType1\u003e,\u003celementType2\u003e,...` (exactly in the same\n  order as in the API description).\n\nYou should _not_ put any whitespaces in those constructs. The consolidated\nexample follows:\n```yaml\n- array:\n  # Here's also an example of passing the namespace as a custom `ns` type\n  # attribute so that you could add or omit it in the code, depending\n  # on your `using` context.\n  - string: { type: vector\u003cstring\u003e, ns: std }\n  - int[]: vector\u003cvector\u003cint\u003e\u003e # A shortcut for { type: ... }\n  - /string-\u003e.+/: # Any additionalProperties map with non-empty structure\n      type: \"QVector\u003cQHash\u003cQString, {{1}}\u003e\u003e\"\n      # You can use imports either as a string or as a list attribute in\n      # configuration; here's the example of using it as a list.\n      imports: [ \u003cQVector\u003e, \u003cQHash\u003e ]\n  - /^string,null|null,string$/:\n      QStringList # Because QString can assume null values\n```\nGenerally though it's better (more readable) to assign a name to such\nan element type and use this name instead - but you have to change the API\ndescription for that.\n\nIt's not possible to use the same shortcut on the _type_ (top) level:\n```yaml\n- int[]: # will not work\n- array:\n  - int: # correct\n```\n\n##### `references`\n\nThis is a section where you configure the behaviour of the analyzer with respect to\n[reference objects](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#reference-object).\nBefore GTAD 0.11, there was a special `$ref` \"type\" that used to work in a way similar to\n`references.replace` subsection.\n\nWhere value matching is performed under this configuration section, configuratin entries match\nrelative paths contained in `$ref` values as follows:\n- if the `$ref` value in the API description is an external ref (contains a path leading to another\n  API description file), it is matched as is;\n- if the `$ref` value is a local reference, i.e. _starts_ with `#`, it is prepended by the relative\n  path of the current API description file, based off the root path of the API description (passed\n  to GTAD at invocation).\n\nAs in other match locations, an entry key has to either match the value in the API description\nentirely byte by byte, or be a regular expression enclosed in `/`.\n\nThe `references` section includes the following (all optional) keys.\n\n###### `inline`\n\nThis subsection is a list of patterns (strings or regexes) for schemas that must always be inlined.\nBefore GTAD 0.11, adding `_inline: true` to the type entry served the same purpose.\n\nAs described in the very beginning of the `Usage` section, GTAD usually represents files\nincluded via `$ref` as separate type definitions in separate target files. Aside from the case\nof local `$ref`s there's one more exception to that, when the loaded model turns out to be\n\"trivial\" - containing exactly one schema that has an exactly one parent. In terms of OpenAPI,\nits data definition either consists of a bare `type`, or itself is a reference object - basically,\nan alias for another type. In that case, GTAD will replace usages of this schema with usages of\nthe original type and eliminate the schema from the generated files entirely (both\nthe definition and all usages).\n\nIf a given `$ref` matches any entry in the `inline` list, GTAD will attempt to apply the same\noptimisation even if the loaded schema is non-trivial. This is useful in cases where an additional\nlevel of indirection complicates the code without bringing value; e.g., you can unroll a top-level\nresponse object to a series of response parameters this way. Not all schemas can be inlined;\nif the $ref'ed schema itself consists of a `$ref` object _and_ parameters on top of that\n(more generally: if there's an `allOf` instance with more than one list entry in the API\ndescription) such schema will be imported as usual regardless of the `_inline` value - that is,\nthe type will be defined separately and used at the place of reference, with imports added\nin the referring file.\n\nAs of GTAD 0.11 (and before), there's no way to force generation of a full-fledged definition for\na trivial schema (pre-0.11, `_inline: false` did nothing).\n\n###### `replace`\n\nThis is a dictionary from patterns to `\u003ctargetTypeSpec\u003e` entries (see `types` section above). If\na matching entry in this section is found for a given `$ref` value, it is used either to override\nsome of those types with another type entirely or to decorate usages  of the target schema with\nadditional attributes - similar to the effect of `types.schema` but applied before any resolution\ntakes place. A `type` key provided for a matching pattern means that the referenced schema in\nthe API description shall be entirely ignored and the target type provided under `type` (with\nadditional attributes, if any are defined next to it) shall be used instead. This allows to skip\ngeneration of type definitions (and even whole files containing those), using a type defined\nin the target language/SDK instead.\nFor example:\n```yaml\nreferences:\n  # Coerce all types from files that have the path ending with \"event.yaml\" to type EventPtr\n  # imported from \"events.h\"; the target API description files won't be opened at all\n  /event.yaml$/: { type: EventPtr, imports: '\"events.h\"' }\n  # For all other ref'ed types, resolve references as usual and set the 'referenced' attribute\n  //: { referenced: }\n```\n\nBeware: supplying `type` in a catch-all (`//`) node in this section (e.g., `- //: { type: Ref }`)\nwill lead to substitution of _all_ not explicitly mentioned reference objects with the type\nspecified in this node. This is most likely not what you would want to do.\n\n###### `importRenderer`\n\nThe import renderer mechanism has been introduced back in GTAD 0.8 but was configured by supplying\n`_importRenderer` attribute for each type that needs it (effectively, for each externally defined\n`schema`). Since GTAD 0.11, one renderer is configured for all imports that are not spelled out\nexplicitly in the configuration (i.e. if there's an `import` attribute then `importRenderer`\nis not used for it).\n\nAn import renderer is a Mustache template called in the context where a given import is stored\nin two forms: in complete but possibly half-baked (we'll get to that in a minute) form, and in a split form, as a Mustache list of path components comprising it. These two forms are placed in\n`{{_}}` and `{{#segments}}` respectively. To give an example, if the import path is\n`events/event_loader.h`, the Mustache context would be:\n```yaml\n{{_}}: 'events/event_loader.h' # without quotes\n{{#segments}}: [ 'events', 'event_loader.h' ]\n```\nFor simple cases when an import is provided verbatim in `gtad.yaml`, the default import renderer\n(that simply inserts the contents of `{{_}}`) works just fine. However, when it comes to imports\nproduced from reference objects in the API description, `{{_}}` will store something like\n`csapi/definitions/filter` (base output directory and the path _stem_ - that is, a path to a file\nwithout its extension). To convert that to something usable, one would almost always need\nto override the import renderer, for example:\n```yaml\nreference:\n  importRenderer: '\"{{#segments}}{{_}}{{#_join}}/{{/_join}}{{/segments}}.h\"'\n  # ...\n```\n`{{#join}}` in the example above is a predefined partial coming in any list context (see \"Data\nmodel exposed to Mustache\" below); you can also define your own Mustache constants and partials\nin `gtad.yaml` and use them within import renderers.\n\n#### Printer configuration\n\nThe printer is essentially a Mustache generator that receives a certain context (mostly resembling\nJSON structure) produced from the model made by the analyzer and from additional definitions,\nas described below. For that reason, it's essential that you get acquainted with Mustache language\nand its vocabulary; [the entire Mustache specification](https://mustache.github.io/mustache.5.html)\nis a 5-minute read but the following section gives a quick overview of what's available. Originally\nMustache was made to render HTML but GTAD reconfigures the generator for C++ instead (so you\ndon't need to worry about `\u0026`-escaping etc.).\n\n##### Quick introduction into Mustache\nMustache template syntax boils down to 4 tag types:\n- `{{variable}}` - direct substitution for a literal or result of a predefined\n  0-argument function (a lambda) stored in the context under that name.\n- `{{#section}}text{{/section}}` - the value stored in the context under that\n  name is applied to a block between the opening and closing tags. Depending\n  on the type of that value, it can be:\n  - a genuine _section_, if the context has a hashmap for that name, or\n    a literal or 0-argument function evaluating to non-false; the inner block\n    is printed with substitution according to the \"derived\" context, which is\n    the previously effective (inherited) context overloaded with this hashmap\n    (if the section corresponds to a variable, no overloading occurs);\n  - iteration over a _list_ - if the context has a list for that name,\n    the inner block is rendered once for each element of the list, with\n    substitutions done according to the \"derived\" context (see above) for that\n    element of the list;\n  - a 1-argument _lambda_ - if the context has a (predefined, in case of GTAD)\n    function with that name, the function gets the inner block and renders it,\n    optionally using the current context (definition of new lambdas without\n    code rebuilding is unfortunately impossible due to the compiled nature\n    of C++ and the lack of dynamically loaded plugins framework in GTAD);\n- `{{\u003epartial}}` - somewhat similar to `{{variable}}` but the _result_ of\n  substitution is treated as a Mustache template itself, meaning that Mustache\n  goes through it looking for more tags to substitute.\n- `{{^invertedSection}}{{/invertedSection}}` - the same as a _genuine section_\n  except that it checks that a particular value is _false_ in the current\n  context (i.e. it's either absent or evaluates to false) and only renders\n  the inner block if the value is not found. No context overloading occurs as\n  there's nothing to overload it with.\n\nAuxiliary tag types include a `{{!comment}}` tag and delimiter reassignment\n(e.g., `{{=\u003c% %\u003e=}}` switches from the `{{`/`}}` pair to `\u003c%`/`%\u003e`)\n\nAs of GTAD 0.7, the printer configuration is stored in the top-level\n`mustache` node and includes the following parts:\n\n##### `delimiter`\nSince GTAD 0.8, Mustache delimiters can be reassigned to a different pair. This\nmay be necessary to comfortably work with languages like Julia that use braces\nfor template specialisation (see #42). The value must be a string, with the\nopening and closing sequences separated by a whitespace; e.g.:\n`delimiter: '%| |%'\nreplaces `{{` with `%|` and `}}` with `|%`.\n\nP.S. Previous versions accepted `_delimiter` under `constants` - unfortunately,\n     it never could practically serve the intended purpose is it had to be\n     defined in the beginning of every single Mustache snippet (file, constant\n     or partial). Due to a significant change in behavior, the old location\n     is _not_ supported any more.\n\n##### `constants`\nThis is a string-to-string map that forms a part of the context for the Mustache\ntemplating engine. Strings provided as keys correspond to Mustache _variables_\nand values, respectively, are values of those variables. No further\ninterpolation of Mustache constructs takes place. Using of a constant `name` in\nMustache code is as simple as `{{name}}`.\n\n##### `partials`\nThis string-to-mustache map is passed as is to the Mustache generator;\nstrings defined here are treated as Mustache _partials_; use them to\nfactor out often-used Mustache snippets in a manner you would use functions in\na programming language. Using one partial from another is perfectly fine; the\nconfiguration file from libQuotient has several examples of such\ninclusion. The standard Mustache syntax is used: to use a partial with the name\n`myPartial` put `{{\u003emyPartial}}` into your Mustache code and define\n`myPartial: '(definition)'` in the configuration file. Since GTAD 0.7 you can\nalso include a partial defined in another file using the same syntax:\n`{{\u003epath/to/file}}` includes (and interpolates as Mustache code in its turn)\na file with the path `path/to/file` or, if that is not found,\n`path/to/file.mustache`.\n\n##### `templates`\nThis consists of two maps of extensions for generated files to Mustache\n_templates_ used to generate each file: one map under `api` for API operation\ndescriptions and another one under `data` for data schemas. For a given\nlanguage, this is fairly static: in case of C/C++, it's likely to look like:\n```yaml\ntemplates:\n  data:\n    .h: \"{{\u003edata.h.mustache}}\"\n    .cpp: \"{{\u003edata.cpp.mustache}}\" # if needed\n  api:\n    .h: \"{{\u003eoperation.h.mustache}}\"\n    .cpp: \"{{\u003eoperation.cpp.mustache}}\" # if needed\n```\nThis instructs GTAD to take the original file (API or data), strip `.yml` or\n`.yaml` extension if it has one (other extensions will be preserved) and\ngenerate two files (with `.h` and `.cpp` extensions respectively) for each\nkind, using the respective Mustache template (that boils down to including\na partial from the respective `.mustache` files).\n\n##### `outFilesList`\nThis node is not used in libQuotient but is there for convenience and \npossible future use. The value for this key specifies the name of the file that\nwill have the full list of generated file names upon GTAD completion. This can\nfurther be used, e.g., in a build system to include generated files into the \nbuild sequence. The target file is not a Mustache template; its contents will\nbe entirely overwritten on every GTAD run.\n\n##### Mustache tips and tricks\n\nMustache does not know anything about the target language and only does minimal\nwork to collapse/eliminate linebreaks (basically - if there's nothing on the\nline except Mustache tags the extra linebreak will be eliminated). To relieve\nthe developer from having to position Mustache tags in a very specific way\nonly to get the formatting right GTAD 0.9 calls clang-format on the generated\nfiles as the final stage (GTAD 0.8 and before did not do that but it was\nstill possible to achieve the same effect by calling clang-format after GTAD\n- libQuotient used to do that in its CMakeLists.txt, in particular). If you\nstill need some way to eliminate extra linebreaks not removed by clang-format\nnote that the ending `}}` of any tag can be put on a new line. The minimal\nway to consume a nasty linebreak is to just put a Mustache comment as follows:\n```handlebars\n{{!\n}}\n```\n\nTODO: more tips and tricks\n\n#### Data model exposed to Mustache\n\n##### Predefined \nFor now, GTAD provides one predefined Mustache tag. There might be more, eventually.\n- `_titleCase` - does what you expect it to do to the passed text, e.g.\n`{{#_titleCase}}plain_text{{/_titleCase}}` becomes `PlainText`. It does not support locales for now\nbut this may change in the future.\n\nGTAD versions before 0.11 had `_cap`, `_toupper` and `_tolower` tags that are no more used and were\ntherefore discontinued. Also, `@filePartial` that allowed to load a Mustache template from another\nfile before GTAD 0.7, was removed as external files inclusion now works with the native partial\nsyntax: `{{\u003ename}}` would first try to load a partial from the context (`gtad.yaml`); failing\nthat, from the file named `name`; and as a last resort, from the file named `name.mustache`.\n\nGTAD has a few extensions to _lists_ compared to original Mustache:\n- on the same level with the list `l` an additional boolean variable with the name `l?` (with\n  the question mark suffix) is set to `true`. This allows you to write templates that get\n  substituted no more than once even when a variable is a list (see the example below). Before\n  version 0.10.2 GTAD had [a bug](https://github.com/KitsuneRal/gtad/issues/50) not resetting\n  `l?` to false when lists with the same name were nested; 0.10.2 and later versions allow to nest\n  lists with the same name without side effects.\n- inside the list, a boolean variable `_join` is set to true for all elements\n  except the last one. For (eventual) compatibility with Mustache templates\n  used in swagger-codegen, there's a synonym `hasMore` equal to `_join`.\n- because the above variables have to be created under the list context,\n  lists of literals are exposed to templates as lists of hashmaps, with the\n  original element value accessed at `{{_}}` instead of `{{.}}` that is\n  usual for Mustache.\n  \nThe following example demonstrates list-related tags coming together.\nThe template:\n```handlebars\nThe list{{#list?}}: {{#list}}{{_}}{{#_join}}, {{/_join}}{{/list}}{{/list?\n}}{{!See the note about linebreaks in \"Tips and tricks\" above\n}}{{^list?}} is empty{{/list?}}\n```\nFor the context: `{ \"list\": [1, 2, 3] }` the output will be:\n`The list: 1, 2, 3`; for the empty context, it will be: `The list is empty`.\n  \n\n##### API data model\n\nTODO\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquotient-im%2Fgtad","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fquotient-im%2Fgtad","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fquotient-im%2Fgtad/lists"}