{"id":22707506,"url":"https://github.com/carueda/tscfg","last_synced_at":"2025-04-04T22:06:51.695Z","repository":{"id":3381500,"uuid":"49305108","full_name":"carueda/tscfg","owner":"carueda","description":"Schema-first, boilerplate-free, type-safe access to configuration properties in Java and Scala","archived":false,"fork":false,"pushed_at":"2025-03-13T15:59:32.000Z","size":1237,"stargazers_count":109,"open_issues_count":9,"forks_count":18,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-03-28T21:09:04.551Z","etag":null,"topics":["configuration","immutable","java","pojo","scala","schema","typesafe","typesafe-config"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/carueda.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","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-01-09T00:58:42.000Z","updated_at":"2025-03-14T21:07:03.000Z","dependencies_parsed_at":"2024-11-04T20:29:41.490Z","dependency_job_id":"ce4e0a1b-3be3-4abb-9e39-4432dcafc734","html_url":"https://github.com/carueda/tscfg","commit_stats":{"total_commits":434,"total_committers":12,"mean_commits":"36.166666666666664","dds":"0.36866359447004604","last_synced_commit":"9baad596231c29169842442a98cbe8392c52678d"},"previous_names":[],"tags_count":59,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carueda%2Ftscfg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carueda%2Ftscfg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carueda%2Ftscfg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carueda%2Ftscfg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/carueda","download_url":"https://codeload.github.com/carueda/tscfg/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247256112,"owners_count":20909240,"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":["configuration","immutable","java","pojo","scala","schema","typesafe","typesafe-config"],"created_at":"2024-12-10T10:13:13.572Z","updated_at":"2025-04-04T22:06:51.677Z","avatar_url":"https://github.com/carueda.png","language":"Scala","readme":"[![Build Status](https://github.com/carueda/tscfg/actions/workflows/ci.yml/badge.svg)](https://github.com/carueda/tscfg/actions)\n[![Coverage Status](https://coveralls.io/repos/github/carueda/tscfg/badge.svg?branch=main)](https://coveralls.io/github/carueda/tscfg?branch=main)\n[![Known Vulnerabilities](https://snyk.io/test/github/carueda/tscfg/badge.svg?targetFile=build.sbt)](https://snyk.io/test/github/carueda/tscfg?targetFile=build.sbt)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://makeapullrequest.com/)\n[![Scala Steward badge](https://img.shields.io/badge/Scala_Steward-helping-blue.svg?style=flat\u0026logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAQCAMAAAARSr4IAAAAVFBMVEUAAACHjojlOy5NWlrKzcYRKjGFjIbp293YycuLa3pYY2LSqql4f3pCUFTgSjNodYRmcXUsPD/NTTbjRS+2jomhgnzNc223cGvZS0HaSD0XLjbaSjElhIr+AAAAAXRSTlMAQObYZgAAAHlJREFUCNdNyosOwyAIhWHAQS1Vt7a77/3fcxxdmv0xwmckutAR1nkm4ggbyEcg/wWmlGLDAA3oL50xi6fk5ffZ3E2E3QfZDCcCN2YtbEWZt+Drc6u6rlqv7Uk0LdKqqr5rk2UCRXOk0vmQKGfc94nOJyQjouF9H/wCc9gECEYfONoAAAAASUVORK5CYII=)](https://scala-steward.org)\n\n\n## tscfg\n\ntscfg is a command line tool that takes a configuration _schema_\nparseable by [Typesafe Config](https://github.com/lightbend/config)\nand generates all the boilerplate to make the definitions\navailable in type-safe, immutable objects\n(POJOs/records for Java, case classes for Scala).\nField comments are captured as well, reflected as javadoc or scala doc comments.\n\nThe generated code only depends on the Typesafe Config library.\n\n\n- [status](#status)\n- [configuration schema](#configuration-schema)\n- [running tscfg](#running-tscfg)\n  - [maven plugin](#maven-plugin)\n  - [gradle plugin](#gradle-plugin)\n- [configuration access](#configuration-access)\n- [supported types](#supported-types)\n  - [basic types](#basic-types)\n  - [size-in-bytes](#size-in-bytes)\n  - [durations](#durations)\n  - [list type](#list-type)\n  - [object type](#object-type)\n  - [optional object or list](#optional-object-or-list)\n  - [shared objects](#shared-objects)\n    - [shared object inheritance](#shared-object-inheritance)\n  - [enum](#enum)\n- [configuration template](#configuration-template)\n- [FAQ](#faq)\n- [tests](#tests)\n\n\n### status\n\nThe tool supports all types handled by Typesafe Config\n(string, int, long, double, boolean, duration, size-in-bytes, list, object)\nand has great test coverage.\nPossible improvements include a more standard command line interface,\na proper tscfg library,\nand perhaps a revision of the syntax for types.\nFeel free to fork, enter issues/reactions, submit PRs, etc.\n\n\n## configuration schema\n\nIn tscfg's approach, the configuration schema itself\ncan be captured in any source parseable by Typesafe Config,\nso the familiar syntax/format and loading mechanisms are used.\n\nFor example, from this configuration:\n\n```hocon\nservice {\n  url = \"https://example.net/rest\"\n  poolSize = 32\n  debug = true\n  factor = 0.75\n}\n```\n\ntscfg will generate the following (javadoc, constructors and other methods omitted):\n\n- Java:\n\n    - With records (`--java:records`):\n\n        ```java\n        public record Cfg(Service service) {\n            public record Service(\n                boolean debug,\n                double factor,\n                int poolSize,\n                String url\n            ) {}\n        }\n        ```\n        Nesting of configuration properties is captured via inner records.\n\n    - POJOs:\n\n        ```java\n        public class Cfg {\n          public final Service service;\n          public static class Service {\n            public final boolean debug;\n            public final double factor;\n            public final int poolSize;\n            public final String url;\n          }\n        }\n        ```\n        Nesting of configuration properties is captured via inner static classes.\n\n\n- Scala:\n\n    ```scala\n    case class Cfg(\n      service : Cfg.Service\n    )\n    object Cfg {\n      case class Service(\n        debug : Boolean,\n        factor : Double,\n        poolSize : Int,\n        url : String\n      )\n    }\n    ```\n    Nesting of configuration properties is captured via nested companion objects.\n\nThe tool determines the type of each field according to the given value\nin the input configuration.\nUsed in this way, all fields are considered optional, with the given value as the default.\n\n**But this wouldn't be flexible enough!**\nTo allow the specification of\n**required fields**,\n**explicit types**,\nand **default values**,\na string with a simple syntax as follows can be used\n(illustrated with the integer type):\n\n| field schema | meaning | java type / default | scala type / default\n|---|---|---|---|\n| a: \"int\"          | required integer | `int` / no default | `Int` / no default\n| a: \"int \u0026vert; 3\" | optional integer with default value `3` | `int` / `3` | `Int`/ `3`\n| a: \"int?\"         | optional integer | `Integer` / `null`(*) | `Option[Int]` / `None`\n\n\u003e [!note]\n\u003e - (*) You can use the `--java:optionals` flag to generate `Optional\u003cT\u003e` instead of `null`.\n\u003e - The type syntax is still subject to change.\n\nThe following is a complete example exercising this mechanism.\n\n```hocon\nendpoint {\n  path: \"string\"\n  url: \"String | http://example.net\"\n  serial: \"int?\"\n  interface {\n    port: \"int | 8080\"\n  }\n}\n```\n\nFor Java, this basically becomes the immutable class:\n\n```java\npublic class JavaExampleCfg {\n  public final Endpoint endpoint;\n\n  public static class Endpoint {\n    public final int intReq;\n    public final Interface_ interface_;\n    public final String path;\n    public final Integer serial;\n    public final String url;\n\n    public static class Interface_ {\n      public final int port;\n      public final String type;\n    }\n  }\n}\n```\n\nAnd for Scala:\n\n```scala\ncase class ScalaExampleCfg(\n  endpoint : ScalaExampleCfg.Endpoint\n)\n\nobject ScalaExampleCfg {\n  case class Endpoint(\n    intReq    : Int,\n    interface : Endpoint.Interface,\n    path      : String,\n    serial    : Option[Int],\n    url       : String\n  )\n\n  object Endpoint {\n    case class Interface(\n      port   : Int,\n      `type` : Option[String]\n    )\n  }\n}\n```\n\n## running tscfg\n\nYou will need a JRE 8+ and the latest fat JAR (tscfg-x.y.z.jar)\nfrom the [releases](https://github.com/carueda/tscfg/releases).\n\n\u003e Or run `sbt assembly` (or `sbt ++2.13.7 assembly`)\n\u003e under a clone of this repo to generate the fat jar.\n\n```\n$ java -jar tscfg-x.y.z.jar\n\ntscfg x.y.z\nUsage:  tscfg.Main --spec inputFile [options]\nOptions (default):\n  --pn \u003cpackageName\u003e                                     (tscfg.example)\n  --cn \u003cclassName\u003e                                       (ExampleCfg)\n  --dd \u003cdestDir\u003e                                         (/tmp if existing or OS dependent temp dir)\n  --java                generate java code               (the default)\n  --java:getters        generate getters (see #31)       (false)\n  --java:records        generate records                 (false)\n  --java:optionals      use optionals                    (false)\n  --scala               generate scala code              (java)\n  --scala:bt            use backticks (see #30)          (false)\n  --durations           use java.time.Duration           (false)\n  --no-doc              do not capture doc comments      (see #312)\n  --all-required        assume all properties are required (see #47)\n  --tpl \u003cfilename\u003e      generate config template         (no default)\n  --tpl.ind \u003cstring\u003e    template indentation string      (\"  \")\n  --tpl.cp \u003cstring\u003e     prefix for template comments     (\"##\")\n  --withoutTimestamp    generate header w/out timestamp  (false)\nOutput is written to $destDir/$className.ext\n```\n\nSo, to generate the Java class `tscfg.example.ExampleCfg` with the example above\nsaved in a file `example.spec.conf`, you can run:\n\n```shell\n$ java -jar tscfg-x.y.z.jar --spec example.spec.conf\n\nparsing: example.spec.conf\ngenerating: /tmp/ExampleCfg.java\n```\n\n### maven plugin\n\nPlease see [tscfg-maven-plugin](https://github.com/timvlaer/tscfg-maven-plugin).\n\n### gradle plugin\n\nPlease see [tscfg-plugin-gradle](https://github.com/aleris/tscfg-plugin-gradle).\n\n## configuration access\n\nAccess to a configuration instance is via usual Typesafe Config mechanism\nas appropriate for your application, for example, to load the default configuration:\n\n```java\nConfig tsConfig = ConfigFactory.load().resolve()\n```\n\nor from a given file:\n\n```java\nConfig tsConfig = ConfigFactory.parseFile(new File(\"my.conf\")).resolve();\n```\n\nNow, to access the configuration fields, instead of, for example:\n```java\nConfig endpoint = tsConfig.getConfig(\"endpoint\");\nString path    = endpoint.getString(\"path\");\nInteger serial = endpoint.hasPathOrNull(\"serial\") ? endpoint.getInt(\"serial\") : null;\nint port       = endpoint.hasPathOrNull(\"port\")   ? endpoint.getInt(\"interface.port\") : 8080;\n```\n\nyou can:\n\n1. Create the tscfg generated wrapper:\n\n    ```java\n    ExampleCfg cfg = new ExampleCfg(tsConfig);\n    ```\n    which will make all verifications about required settings and associated types.\n    In particular, as is typical with Config use, an exception will be thrown if this verification fails.\n\n2. Then, while enjoying full type safety and the code completion and navigation capabilities of your editor or IDE:\n\n    ```java\n    String path    = cfg.endpoint.path;\n    Integer serial = cfg.endpoint.serial;\n    int port       = cfg.endpoint.interface_.port;\n    ```\n\nAn object reference will never be `null` (or `Optional.empty()`) (`None` in Scala) if the corresponding field is required according to\nthe schema. It will only be `null` (or `Optional.empty()`) (`None` in Scala) if it is marked optional with no default value and\nhas been omitted in the input configuration.\n\nWith this [example schema](schemahttps://github.com/carueda/tscfg/blob/main/src/main/tscfg/example/example.spec.conf),\nthe generated Java code looks [like this](https://github.com/carueda/tscfg/blob/main/src/main/java/tscfg/example/JavaExampleCfg.java)\nand an example of use [like this](https://github.com/carueda/tscfg/blob/main/src/main/java/tscfg/example/JavaUse.java).\n\nFor Scala\nthe generated code looks [like this](https://github.com/carueda/tscfg/blob/main/src/main/scala/tscfg/example/ScalaExampleCfg.scala)\nand an example of use [like this](https://github.com/carueda/tscfg/blob/main/src/main/scala/tscfg/example/scalaUse.scala).\n\n## supported types\n\n### basic types\n\nThe following basic types are supported:\n\n| type in schema                       | java type:\u003cbr /\u003e req / opt  | scala type:\u003cbr /\u003e req / opt\n|--------------------------------------|--------------------------|---------------------------------\n| `string`                             | `String`   / `String`    | `String`   / `Option[String]`\n| `int`                                | `int`      / `Integer`   | `Int`      / `Option[Int]`\n| `long`                               | `long`     / `Long`      | `Long`     / `Option[Long]`\n| `double`                             | `double`   / `Double`    | `Double`   / `Option[Double]`\n| `boolean`                            | `boolean`  / `Boolean`   | `Boolean`  / `Option[Boolean]`\n| `size`                               | `long`     / `Long`      | `Long`     / `Option[Long]`\n| `duration`                           | `long`     / `Long`      | `Long`     / `Option[Long]`\n| `duration` (using `--durations` flag) | `Duration` / `Duration`  | `Duration` / `Option[Duration]`\n\n\u003e [!note]\n\u003e - please read `Optional\u003cT\u003e` instead of the `T` values in the\n    java \"opt\" column above if using the `--java:optionals` flag.\n\u003e - using the `--durations` flag, `java.time.Duration` is used instead of `long` / `Long`. See [durations](#durations) for further information.\n\n\n#### size-in-bytes\n\nThe `size` type corresponds to the\n[size-in-bytes formats](https://github.com/lightbend/config/blob/main/HOCON.md#size-in-bytes-format)\nsupported by the Typesafe library.\nSee [#23](https://github.com/carueda/tscfg/issues/23) for various examples.\n\n\u003e [!note]\n\u003e A setting with a default value like\n\u003e `memory: 50G` (or `memory: \"50G\"`) will not be inferred as with `size` type, but just as a string\n\u003e (with default value `\"50G\"`).\n\u003e For the `size` type effect, you will need to be explicit: `memory: \"size | 50G\"`.\n\u003e See [#42](https://github.com/carueda/tscfg/issues/42).\n\n#### durations\n\nA duration type can be further qualified with a suffix consisting of a colon\nand a desired time unit for the reported value.\nFor example, with the type `\"duration:day\"`, the reported long value will be in day units,\nwith conversion automatically performed if the actual configuration value is given in\nany other unit as supported by Typesafe Config according to the\n[duration format](https://github.com/lightbend/config/blob/main/HOCON.md#duration-format).\n\n[A more complete example](https://github.com/carueda/tscfg/blob/main/src/main/tscfg/example/duration.spec.conf)\nwith some additional explanation:\n\n```hocon\ndurations {\n  # optional duration; reported Long (Option[Long] in scala) is null (None) if value is missing\n  # or whatever is provided converted to days\n  days: \"duration:day?\"\n\n  # required duration; reported long (Long) is whatever is provided\n  # converted to hours\n  hours: \"duration:hour\"\n\n  # optional duration with default value;\n  # reported long (Long) is in milliseconds, either 550,000 if value is missing\n  # or whatever is provided converted to millis\n  millis: \"duration:ms | 550s\"\n\n  ...\n}\n```\nUsing the `--durations` flag, the reported value will be a `java.time.Duration` instead of a `long` / `Long` and the suffix will be ignored:\n`\"duration:hours | 3day\"` is `java.time.Duration.ofDays(3)` if value is missing or whatever is provided converted to a `java.time.Duration`\n\n\n### list type\n\nWith _t_ denoting a handled type, a list of elements of that type\nis denoted `[` _t_ `]`. The corresponding types in Java and Scala are:\n\n| type in schema | java type:\u003cbr /\u003e req / opt  | scala type:\u003cbr /\u003e req / opt\n|---------------|---------------------|--------------------------\n| `[` _t_ `]`   | `List\u003cT\u003e` / `List\u003cT\u003e`   | `List[T]` / `Option[List[T]]`\n\nwhere `T` is the corresponding translation of _t_ in the target language, with\n`List\u003cT\u003e` corresponding to an unmodifiable list in Java, and\n`List[T]` corresponding to an immutable list in Scala.\n\n### object type\n\nAs seen in examples above, each object in the given configuration schema becomes a class.\n\nIt is of course possible to specify a field as a list of objects, for example:\n\n```hocon\npositions: [\n  {\n    lat: double\n    lon: double\n  }\n]\n```\n\nIn Java this basically becomes:\n\n```java\npublic class Cfg {\n  public final java.util.List\u003cCfg.Positions$Elm\u003e positions;\n\n  public static class Positions$Elm {\n    public final double lat;\n    public final double lon;\n  }\n}\n```\n\nand in Scala:\n```scala\ncase class Cfg(\n  positions : List[Cfg.Positions$Elm]\n)\n\nobject Cfg {\n  case class Positions$Elm(\n    lat : Double,\n    lon : Double\n  )\n}\n```\n\n### optional object or list\n\nAn object or a list in the input configuration can be marked optional with\nthe `@optional` annotation (in a comment):\n\n```hocon\n#@optional\nemail {\n  server: string\n  password: string\n}\n\n#@optional\nreals: [ { foo: double } ]\n```\n\nIn Scala this basically becomes:\n\n```scala\ncase class Cfg(\n  email : Option[Cfg.Email],\n  reals : Option[List[Cfg.Reals$Elm]]\n)\n\nobject Cfg {\n  case class Email(\n    password : String,\n    server   : String\n  )\n  case class Reals$Elm(\n    foo : Double\n  )\n}\n```\n\nAs with basic types, the meaning of an optional object or list is that the corresponding\nvalue will be `null` (or `Optional.empty()`) (`None` in Scala) when the corresponding actual entry is missing in\na given configuration instance.\n\n### shared objects\n\nSince version 0.9.94 we started adding support for \"shared objects\" (#54),\na feature that has been enhanced in later versions.\nThis is exercised by using the `@define` annotation:\n\n```hocon\n#@define\nStruct {\n  c: string\n  d: int\n}\n\nexample {\n  a: Struct\n  b: [ Struct ]\n}\n```\n\nIn this example, the annotation will only generate the definition of the\ncorresponding class `Struct` in the wrapper but not the member of that\ntype itself. Then, the type can be referenced for other definitions.\n\n\u003e Note: The `@define` annotation is only supported for objects and enumerations (see below),\n\u003e not for a basic types or lists.\n\n#### shared object inheritance\n\nAs of 0.9.98 shared objects now support simple inheritance by an abstract superclass. The following syntax can be used\nto define a simple inheritance:\n\n```hocon\n#@define abstract\nBaseStruct {\n  a: [string]\n  b: double\n}\n\n#@define extends BaseStruct\nChildStruct {\n  c: string\n  d: string\n}\n\nexample {\n  child: ChildStruct\n}\n```\n\nIn this example, the annotation will generate an abstract class definition of the ``BaseStruct`` as well as a definition\nof ``ChildStruct`` which extends ``BaseStruct``. This inheritance structure simplifies processing of the config with\nstructs that have multiple common fields.\n\nOnly leaf members of the inheritance tree may be instantiable instances, all other shared objects in between have to be\nabstract classes.\nThe following are valid definition comments:\n\n| Comment                          | Meaning                                                                              |\n| :------------------------------- | :----------------------------------------------------------------------------------- |\n| `#@define abstract`              | Root of an inheritance tree                                                          |\n| `#@define abstract extends Foo`   | Intermediate member of the tree, that extends the shared object `Foo`               |\n| `#@define extends Bla`           | Leaf member of the inheritance tree, that extends the (abstract) shared object `Bla` |\n\n\n#### known issues with shared objects\n\n- the current support for shared objects as field types in another shared object is unstable and not yet fully supported\n\n## enum\n\nEnumerations can also be defined and this is done through the\n`@define enum` annotation:\n\n```hocon\n#@define enum\nFruitType = [apple, banana, pineapple]\n\nfruit: FruitType\n\nsomeFruits: [FruitType]\n\nother: {\n  aFruit: FruitType\n}\n```\n\nAs with other uses of `@define`, the enumeration annotation will only generate\nthe enumeration type itself, but the associated name can then be used for other\nfield definitions in your configuration schema.\n\nThe type defined in the example above basically gets translated into Java and Scala\nas follows:\n\n```java\npublic enum FruitType {\n    apple,\n    banana,\n    pineapple;\n}\n```\n\n```scala\nsealed trait FruitType\nobject FruitType {\n  object apple     extends FruitType\n  object banana    extends FruitType\n  object pineapple extends FruitType\n}\n```\n\n## configuration template\n\ntscfg can also generate user-oriented configuration templates from the given\nconfiguration schema.\nSee [this wiki](https://github.com/carueda/tscfg/wiki/template-generation).\n\n\n## FAQ\n\n**But I can just access the configuration values directly with Typesafe Config\nand even put them in my own classes**\n\nSure. However, as the number of configuration properties and levels of nesting increase,\nthe benefits of automated generation of the type-safe, immutable objects,\nalong with the centralized verification, shall become more apparent. All of this\n–worth emphasizing– **based on an explicit *schema* for the configuration.**\n\n**Any tscfg best practice for my development workflow?**\n\nPlease see [this wiki](https://github.com/carueda/tscfg/wiki/workflow).\n\n**Is there any sbt plugin for tscfg that I can use as part of the build for my project?**\n\nNot implemented yet. The issue is [#21](https://github.com/carueda/tscfg/issues/21)\nif you want to add comments or reactions.  PRs are also welcome.\n\n**Can tscfg generate `Optional\u003cT\u003e` for optional fields?**\n\nUse the `--java:optionals` flag for enabling `Optional\u003cT\u003e` instead of `null` for optional fields in java.\n\n**What happened with the generated `toString` method?**\n\nWe think it's more flexible to let client code decide how to render configuration instances\nwhile also recognizing that very likely typical serialization libraries are already being\nused in the application.\nFor example, the demo programs\n[JavaUse](https://github.com/carueda/tscfg/blob/main/src/main/java/tscfg/example/JavaUse.java)\nand [scalaUse](https://github.com/carueda/tscfg/blob/main/src/main/scala/tscfg/example/scalaUse.scala)\nuse [Gson](https://github.com/google/gson) and\n[pprint](https://com-lihaoyi.github.io/PPrint/), respectively.\nAlthough you could also use Typesafe Config itself for rendering purposes, you would be\nusing the original Typesafe Config parsed configuration object, so the rendering won't\nnecessarily be restricted only to the elements captured in the _configuration schema_\nused by tscfg for the generated wrapper.\n\n## tests\n\nhttps://github.com/carueda/tscfg/tree/main/src/test/scala/tscfg\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcarueda%2Ftscfg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcarueda%2Ftscfg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcarueda%2Ftscfg/lists"}