Full Code of microconfig/microconfig for AI

master bd7cf5750d35 cached
518 files
416.5 KB
116.2k tokens
1058 symbols
1 requests
Download .txt
Showing preview only (577K chars total). Download the full file or copy to clipboard to get everything.
Repository: microconfig/microconfig
Branch: master
Commit: bd7cf5750d35
Files: 518
Total size: 416.5 KB

Directory structure:
gitextract_ljxcps6x/

├── .github/
│   ├── scripts/
│   │   ├── decrypt_secring.sh
│   │   ├── native/
│   │   │   ├── Dockerfile-alpine
│   │   │   ├── graalvm-linux.sh
│   │   │   ├── graalvm-mac.sh
│   │   │   ├── graalvm-win.sh
│   │   │   ├── native.bat
│   │   │   └── native.sh
│   │   └── set_gradle_properties.sh
│   └── workflows/
│       ├── build.yml
│       ├── gradlepublish.yml
│       └── release.yml
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── agent.sh
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── lib.gradle
├── lombok.config
├── microconfig-api/
│   ├── build.gradle
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── io/
│       │           └── microconfig/
│       │               └── core/
│       │                   ├── configtypes/
│       │                   │   ├── ConfigType.java
│       │                   │   ├── ConfigTypeFilter.java
│       │                   │   ├── ConfigTypeFilters.java
│       │                   │   └── ConfigTypeRepository.java
│       │                   ├── environments/
│       │                   │   ├── Component.java
│       │                   │   ├── ComponentGroup.java
│       │                   │   ├── Components.java
│       │                   │   ├── Environment.java
│       │                   │   └── EnvironmentRepository.java
│       │                   ├── exceptions/
│       │                   │   └── MicroconfigException.java
│       │                   ├── properties/
│       │                   │   ├── ConfigFormat.java
│       │                   │   ├── DeclaringComponent.java
│       │                   │   ├── PlaceholderResolveStrategy.java
│       │                   │   ├── Properties.java
│       │                   │   ├── PropertiesFactory.java
│       │                   │   ├── Property.java
│       │                   │   ├── PropertySerializer.java
│       │                   │   ├── Resolver.java
│       │                   │   └── TypedProperties.java
│       │                   └── templates/
│       │                       └── Template.java
│       └── test/
│           └── java/
│               └── io/
│                   └── microconfig/
│                       └── core/
│                           ├── configtypes/
│                           │   └── ConfigTypeFiltersTest.java
│                           └── properties/
│                               └── ConfigFormatTest.java
├── microconfig-cli/
│   ├── build.gradle
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── io/
│       │   │       └── microconfig/
│       │   │           ├── CommandLineParamParser.java
│       │   │           ├── MicroconfigMain.java
│       │   │           └── MicroconfigParams.java
│       │   └── resources/
│       │       ├── META-INF/
│       │       │   └── native-image/
│       │       │       ├── jni-config.json
│       │       │       ├── native-image.properties
│       │       │       ├── proxy-config.json
│       │       │       ├── reflect-config.json
│       │       │       └── resource-config.json
│       │       └── log4j2.xml
│       └── test/
│           ├── java/
│           │   └── io/
│           │       └── microconfig/
│           │           ├── CommandLineParamParserTest.java
│           │           ├── MicroconfigMainTest.java
│           │           └── MicroconfigParamsTest.java
│           └── resources/
│               └── repo/
│                   ├── components/
│                   │   └── component/
│                   │       ├── application.yaml
│                   │       └── os.deploy
│                   └── envs/
│                       ├── env1.yaml
│                       ├── env2.yaml
│                       └── env3.yaml
├── microconfig-core/
│   ├── build.gradle
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── io/
│       │           └── microconfig/
│       │               └── core/
│       │                   ├── Microconfig.java
│       │                   ├── MicroconfigRunner.java
│       │                   ├── configtypes/
│       │                   │   ├── CompositeConfigTypeRepository.java
│       │                   │   ├── ConfigTypeImpl.java
│       │                   │   ├── CustomConfigTypeRepository.java
│       │                   │   ├── StandardConfigType.java
│       │                   │   └── StandardConfigTypeRepository.java
│       │                   ├── environments/
│       │                   │   ├── ComponentFactory.java
│       │                   │   ├── ComponentFactoryImpl.java
│       │                   │   ├── ComponentGroupImpl.java
│       │                   │   ├── ComponentImpl.java
│       │                   │   ├── ComponentsImpl.java
│       │                   │   ├── EnvironmentImpl.java
│       │                   │   └── repository/
│       │                   │       ├── ComponentDefinition.java
│       │                   │       ├── ComponentGroupDefinition.java
│       │                   │       ├── EnvInclude.java
│       │                   │       ├── EnvironmentDefinition.java
│       │                   │       ├── EnvironmentException.java
│       │                   │       ├── EnvironmentFile.java
│       │                   │       ├── FileEnvironmentRepository.java
│       │                   │       └── LazyInitEnvRepository.java
│       │                   └── properties/
│       │                       ├── DeclaringComponentImpl.java
│       │                       ├── FileBasedComponent.java
│       │                       ├── OverrideProperty.java
│       │                       ├── PropertiesFactoryImpl.java
│       │                       ├── PropertiesImpl.java
│       │                       ├── PropertiesRepository.java
│       │                       ├── PropertyImpl.java
│       │                       ├── ResolveException.java
│       │                       ├── TypedPropertiesImpl.java
│       │                       ├── io/
│       │                       │   ├── AbstractConfigReader.java
│       │                       │   ├── ConfigIo.java
│       │                       │   ├── ConfigReader.java
│       │                       │   ├── ConfigWriter.java
│       │                       │   ├── properties/
│       │                       │   │   ├── PropertiesConfigIo.java
│       │                       │   │   ├── PropertiesReader.java
│       │                       │   │   └── PropertiesWriter.java
│       │                       │   ├── selector/
│       │                       │   │   ├── ConfigFormatDetector.java
│       │                       │   │   ├── ConfigFormatDetectorImpl.java
│       │                       │   │   ├── ConfigIoFactory.java
│       │                       │   │   └── ConfigIoSelector.java
│       │                       │   └── yaml/
│       │                       │       ├── YamlConfigIo.java
│       │                       │       ├── YamlReader.java
│       │                       │       ├── YamlTree.java
│       │                       │       ├── YamlTreeImpl.java
│       │                       │       └── YamlWriter.java
│       │                       ├── repository/
│       │                       │   ├── ComponentGraph.java
│       │                       │   ├── ComponentGraphImpl.java
│       │                       │   ├── ComponentNotFoundException.java
│       │                       │   ├── CompositePropertiesRepository.java
│       │                       │   ├── ConfigFile.java
│       │                       │   ├── EnvProfilesComponentGraph.java
│       │                       │   ├── FilePropertiesRepository.java
│       │                       │   ├── Include.java
│       │                       │   ├── Includes.java
│       │                       │   └── RawConfig.java
│       │                       ├── resolvers/
│       │                       │   ├── ChainedResolver.java
│       │                       │   ├── RecursiveResolver.java
│       │                       │   ├── expression/
│       │                       │   │   ├── ExpressionEvaluator.java
│       │                       │   │   ├── ExpressionResolver.java
│       │                       │   │   └── functions/
│       │                       │   │       ├── CustomIoApi.java
│       │                       │   │       └── CustomStringApi.java
│       │                       │   └── placeholder/
│       │                       │       ├── Placeholder.java
│       │                       │       ├── PlaceholderBorders.java
│       │                       │       ├── PlaceholderResolver.java
│       │                       │       └── strategies/
│       │                       │           ├── component/
│       │                       │           │   ├── ComponentProperty.java
│       │                       │           │   ├── ComponentResolveStrategy.java
│       │                       │           │   └── properties/
│       │                       │           │       ├── ComponentProperties.java
│       │                       │           │       ├── ConfigDirProperty.java
│       │                       │           │       ├── ConfigRootDirProperty.java
│       │                       │           │       ├── NameProperty.java
│       │                       │           │       └── ResultDirProperty.java
│       │                       │           ├── composite/
│       │                       │           │   └── CompositeResolveStrategy.java
│       │                       │           ├── environment/
│       │                       │           │   ├── EnvProperty.java
│       │                       │           │   ├── EnvironmentResolveStrategy.java
│       │                       │           │   └── properties/
│       │                       │           │       ├── ComponentOrderProperty.java
│       │                       │           │       ├── EnvNameProperty.java
│       │                       │           │       ├── EnvironmentProperties.java
│       │                       │           │       ├── GroupNameProperty.java
│       │                       │           │       ├── IpProperty.java
│       │                       │           │       └── PortOffsetProperty.java
│       │                       │           ├── standard/
│       │                       │           │   └── StandardResolveStrategy.java
│       │                       │           └── system/
│       │                       │               └── SystemResolveStrategy.java
│       │                       ├── serializers/
│       │                       │   ├── ConfigDiff.java
│       │                       │   ├── ConfigResult.java
│       │                       │   └── PropertySerializers.java
│       │                       └── templates/
│       │                           ├── BinaryTemplate.java
│       │                           ├── MustacheTemplateProcessor.java
│       │                           ├── StringTemplate.java
│       │                           ├── TemplateContentPostProcessor.java
│       │                           ├── TemplateDefinition.java
│       │                           ├── TemplateDefinitionParser.java
│       │                           ├── TemplatePattern.java
│       │                           ├── TemplatesService.java
│       │                           └── definition/
│       │                               └── parser/
│       │                                   ├── ArrowNotationParser.java
│       │                                   ├── FromToNotationParser.java
│       │                                   └── SquareBracketsNotationParser.java
│       └── test/
│           ├── java/
│           │   └── io/
│           │       └── microconfig/
│           │           └── core/
│           │               ├── ClasspathReader.java
│           │               ├── MicroconfigRunnerTest.java
│           │               ├── MicroconfigTest.java
│           │               ├── TemplatesTest.java
│           │               ├── configtypes/
│           │               │   ├── CompositeConfigTypeRepositoryTest.java
│           │               │   ├── ConfigTypeImplTest.java
│           │               │   ├── CustomConfigTypeRepositoryTest.java
│           │               │   ├── StandardConfigTypeRepositoryTest.java
│           │               │   └── StandardConfigTypeTest.java
│           │               ├── environments/
│           │               │   ├── ComponentFactoryImplTest.java
│           │               │   ├── ComponentGroupImplTest.java
│           │               │   ├── ComponentImplTest.java
│           │               │   ├── ComponentsImplTest.java
│           │               │   ├── EnvironmentImplTest.java
│           │               │   └── repository/
│           │               │       ├── ComponentDefinitionTest.java
│           │               │       └── FileEnvironmentRepositoryTest.java
│           │               └── properties/
│           │                   ├── ComponentWithEnvTest.java
│           │                   ├── FileBasedComponentTest.java
│           │                   ├── PropertiesImplTest.java
│           │                   ├── PropertyImplTest.java
│           │                   ├── ResolveExceptionTest.java
│           │                   ├── TypedPropertiesImplTest.java
│           │                   ├── io/
│           │                   │   ├── properties/
│           │                   │   │   └── PropertiesConfigIoTest.java
│           │                   │   └── yaml/
│           │                   │       ├── YamlConfigIoTest.java
│           │                   │       └── YamlTreeImplTest.java
│           │                   ├── repository/
│           │                   │   ├── ComponentNotFoundExceptionTest.java
│           │                   │   ├── CompositePropertiesRepositoryTest.java
│           │                   │   ├── EnvProfilesComponentGraphTest.java
│           │                   │   └── IncludeTest.java
│           │                   ├── resolvers/
│           │                   │   ├── expression/
│           │                   │   │   ├── ExpressionResolverTest.java
│           │                   │   │   └── functions/
│           │                   │   │       └── CustomStringApiTest.java
│           │                   │   └── placeholder/
│           │                   │       └── PlaceholderBordersTest.java
│           │                   └── templates/
│           │                       ├── StringTemplatePatternTest.java
│           │                       ├── StringTemplateTest.java
│           │                       └── definition/
│           │                           └── parser/
│           │                               ├── ArrowNotationParserTest.java
│           │                               ├── FromToNotationParserTest.java
│           │                               └── SquareBracketsNotationParserTest.java
│           └── resources/
│               ├── configFormats/
│               │   ├── properties/
│               │   │   └── propLine.properties
│               │   └── yaml/
│               │       ├── list/
│               │       │   ├── list.yaml
│               │       │   └── resultList.yaml
│               │       ├── parse/
│               │       │   ├── inner.yaml
│               │       │   ├── inner2.yaml
│               │       │   ├── mapLikeName.yaml
│               │       │   ├── multilines.yaml
│               │       │   └── simple.yaml
│               │       ├── sortOrder/
│               │       │   ├── initial.yaml
│               │       │   └── result.yaml
│               │       └── tree/
│               │           ├── doubleEscapedResult.yaml
│               │           └── escapedResult.yaml
│               ├── configTypes/
│               │   └── microconfig.yaml
│               ├── envs/
│               │   ├── bad/
│               │   │   └── envs/
│               │   │       ├── bad.json
│               │   │       ├── bad.yaml
│               │   │       ├── bad2.yaml
│               │   │       ├── badGroup.yaml
│               │   │       ├── copy.yaml
│               │   │       └── subfolder/
│               │   │           └── bad2.yaml
│               │   └── good/
│               │       └── envs/
│               │           ├── alias.yaml
│               │           ├── base.yaml
│               │           ├── dev.yaml
│               │           ├── folder/
│               │           │   ├── prod.yaml
│               │           │   └── staging.yaml
│               │           └── test.yaml
│               ├── repo/
│               │   ├── components/
│               │   │   ├── aliases/
│               │   │   │   ├── node/
│               │   │   │   │   ├── expect.aliases
│               │   │   │   │   ├── expect.aliases.node1
│               │   │   │   │   ├── expect.aliases.node3
│               │   │   │   │   └── service.properties
│               │   │   │   ├── placeholderToAlias/
│               │   │   │   │   ├── expect.aliases
│               │   │   │   │   └── service.properties
│               │   │   │   └── placeholderToAliasWithAnotherTipe/
│               │   │   │       ├── aliasType/
│               │   │   │       │   ├── expect.aliases
│               │   │   │       │   └── service.properties
│               │   │   │       └── aliasType2/
│               │   │   │           ├── service.process
│               │   │   │           └── service.properties
│               │   │   ├── configType/
│               │   │   │   ├── appType/
│               │   │   │   │   ├── application.yaml
│               │   │   │   │   └── expect.dev
│               │   │   │   ├── application.process
│               │   │   │   ├── application.yaml
│               │   │   │   ├── expect.dev
│               │   │   │   └── processType/
│               │   │   │       └── application.process
│               │   │   ├── doubleQuatesWithKey/
│               │   │   │   ├── application.yaml
│               │   │   │   └── expect.env
│               │   │   ├── empty/
│               │   │   │   ├── expect.uat
│               │   │   │   └── service.properties
│               │   │   ├── envChange/
│               │   │   │   ├── 01/
│               │   │   │   │   ├── include-client/
│               │   │   │   │   │   ├── application.yaml
│               │   │   │   │   │   ├── expect.dev
│               │   │   │   │   │   └── expect.uat1
│               │   │   │   │   ├── include-client2/
│               │   │   │   │   │   ├── application.uat1.yaml
│               │   │   │   │   │   ├── application.yaml
│               │   │   │   │   │   ├── expect.dev
│               │   │   │   │   │   └── expect.uat1
│               │   │   │   │   └── includeOtherEnv/
│               │   │   │   │       ├── application.yaml
│               │   │   │   │       ├── expect.dev
│               │   │   │   │       └── expect.uat1
│               │   │   │   ├── contextChange/
│               │   │   │   │   ├── application.dev.yaml
│               │   │   │   │   ├── application.prod.yaml
│               │   │   │   │   ├── application.test.yaml
│               │   │   │   │   ├── application.yaml
│               │   │   │   │   ├── expect.dev
│               │   │   │   │   └── expect.uat
│               │   │   │   ├── envInFile/
│               │   │   │   │   ├── application.prod.yaml
│               │   │   │   │   ├── application.yaml
│               │   │   │   │   ├── expect.prod-a
│               │   │   │   │   └── expect.prod-b
│               │   │   │   ├── envInclude/
│               │   │   │   │   └── application.yaml
│               │   │   │   ├── profiles/
│               │   │   │   │   ├── prof1/
│               │   │   │   │   │   ├── application.yaml
│               │   │   │   │   │   └── expect.profs
│               │   │   │   │   └── prof2/
│               │   │   │   │       ├── application.LONG.yaml
│               │   │   │   │       └── application.yaml
│               │   │   │   └── transitiveEnvChange/
│               │   │   │       ├── tec01/
│               │   │   │       │   ├── application.yaml
│               │   │   │       │   ├── expect.dev
│               │   │   │       │   └── expect.prod
│               │   │   │       ├── tec02/
│               │   │   │       │   └── application.yaml
│               │   │   │       ├── tec03/
│               │   │   │       │   └── application.yaml
│               │   │   │       └── tec04/
│               │   │   │           ├── application.dev.yaml
│               │   │   │           ├── application.prod.yaml
│               │   │   │           └── application.yaml
│               │   │   ├── envIpTest/
│               │   │   │   ├── ip1/
│               │   │   │   │   ├── expect.uat
│               │   │   │   │   └── service.properties
│               │   │   │   └── ip2/
│               │   │   │       ├── expect.uat
│               │   │   │       └── service.properties
│               │   │   ├── envProps/
│               │   │   │   ├── expect.uat
│               │   │   │   └── service.properties
│               │   │   ├── exceptions/
│               │   │   │   ├── IncludeBad/
│               │   │   │   │   ├── includeBadDelimiter/
│               │   │   │   │   │   ├── application.prop.properties
│               │   │   │   │   │   ├── application.yl.yaml
│               │   │   │   │   │   ├── exception.prop
│               │   │   │   │   │   └── exception.yl
│               │   │   │   │   ├── includeBadEnv/
│               │   │   │   │   │   ├── application.includeNotUniqueComponents.yaml
│               │   │   │   │   │   ├── application.includeParseError.yaml
│               │   │   │   │   │   ├── exception.includeNotUniqueComponents
│               │   │   │   │   │   └── truncate.includeParseError
│               │   │   │   │   ├── includeBadExpression/
│               │   │   │   │   │   ├── application.yaml
│               │   │   │   │   │   └── exception.dev
│               │   │   │   │   ├── includeBadInclude/
│               │   │   │   │   │   ├── application.yaml
│               │   │   │   │   │   └── exception.dev
│               │   │   │   │   └── includeBadPlaceholder/
│               │   │   │   │       ├── application.component.yaml
│               │   │   │   │       ├── application.key.yaml
│               │   │   │   │       ├── exception.component
│               │   │   │   │       └── exception.key
│               │   │   │   ├── bad/
│               │   │   │   │   ├── badDelimiter/
│               │   │   │   │   │   ├── application.prop.properties
│               │   │   │   │   │   ├── application.yl.yaml
│               │   │   │   │   │   ├── exception.prop
│               │   │   │   │   │   └── exception.yl
│               │   │   │   │   ├── badEnv/
│               │   │   │   │   │   ├── application.yaml
│               │   │   │   │   │   ├── exception.notUniqueComponents
│               │   │   │   │   │   └── truncate.parseError
│               │   │   │   │   ├── badExpression/
│               │   │   │   │   │   ├── application.yaml
│               │   │   │   │   │   └── exception.dev
│               │   │   │   │   ├── badInclude/
│               │   │   │   │   │   ├── application.yaml
│               │   │   │   │   │   └── exception.dev
│               │   │   │   │   ├── badPlaceholder/
│               │   │   │   │   │   ├── application.component.yaml
│               │   │   │   │   │   ├── application.key.yaml
│               │   │   │   │   │   ├── exception.component
│               │   │   │   │   │   └── exception.key
│               │   │   │   │   └── cyclic/
│               │   │   │   │       ├── cyclicDetect/
│               │   │   │   │       │   ├── exception.dev
│               │   │   │   │       │   └── service.properties
│               │   │   │   │       └── cyclicDetectBetweenConfigTypes/
│               │   │   │   │           ├── exception.dev
│               │   │   │   │           ├── process.process
│               │   │   │   │           └── service.properties
│               │   │   │   └── placeholderToBad/
│               │   │   │       ├── placeholderToBadDelimiter/
│               │   │   │       │   ├── application.prop.properties
│               │   │   │       │   ├── application.yl.yaml
│               │   │   │       │   ├── exception.prop
│               │   │   │       │   └── exception.yl
│               │   │   │       ├── placeholderToBadEnv/
│               │   │   │       │   ├── application.notUniqueComponents.yaml
│               │   │   │       │   ├── application.parseError.yaml
│               │   │   │       │   ├── exception.notUniqueComponents
│               │   │   │       │   └── trunc.parseError
│               │   │   │       ├── placeholderToBadExpression/
│               │   │   │       │   ├── application.yaml
│               │   │   │       │   └── exception.dev
│               │   │   │       ├── placeholderToBadInclude/
│               │   │   │       │   ├── application.yaml
│               │   │   │       │   └── exception.dev
│               │   │   │       └── placeholderToBadPlaceholder/
│               │   │   │           ├── application.component.yaml
│               │   │   │           ├── application.key.yaml
│               │   │   │           ├── exception.component
│               │   │   │           └── exception.key
│               │   │   ├── ignore/
│               │   │   │   ├── ignored/
│               │   │   │   │   ├── expect.uat
│               │   │   │   │   └── service.properties
│               │   │   │   ├── notIgnored/
│               │   │   │   │   ├── expect.uat
│               │   │   │   │   └── service.properties
│               │   │   │   └── notIgnored2/
│               │   │   │       ├── expect.uat
│               │   │   │       └── service.properties
│               │   │   ├── includeDefault/
│               │   │   │   ├── id-default/
│               │   │   │   │   ├── application.dev.yaml
│               │   │   │   │   ├── application.yaml
│               │   │   │   │   ├── expect.dev
│               │   │   │   │   └── expect.test
│               │   │   │   ├── id-middle/
│               │   │   │   │   ├── application.yaml
│               │   │   │   │   ├── expect.dev
│               │   │   │   │   └── expect.test
│               │   │   │   └── id-root/
│               │   │   │       ├── application.yaml
│               │   │   │       ├── expect.dev
│               │   │   │       └── expect.test
│               │   │   ├── includeTest/
│               │   │   │   ├── cyclicInclude/
│               │   │   │   │   ├── ci1/
│               │   │   │   │   │   ├── expect.uat
│               │   │   │   │   │   └── service.properties
│               │   │   │   │   └── ci2/
│               │   │   │   │       ├── expect.uat
│               │   │   │   │       └── service.properties
│               │   │   │   ├── includeOrder/
│               │   │   │   │   ├── inOrder1/
│               │   │   │   │   │   ├── expect.dev
│               │   │   │   │   │   ├── expect.uat
│               │   │   │   │   │   ├── service.dev.properties
│               │   │   │   │   │   └── service.uat.properties
│               │   │   │   │   ├── inOrder2/
│               │   │   │   │   │   ├── expect.some
│               │   │   │   │   │   └── service.properties
│               │   │   │   │   └── inOrder3/
│               │   │   │   │       ├── expect.some
│               │   │   │   │       └── service.properties
│               │   │   │   ├── includeWithEnvChange/
│               │   │   │   │   ├── ic1/
│               │   │   │   │   │   ├── expect.dev
│               │   │   │   │   │   └── service.dev.properties
│               │   │   │   │   ├── ic2/
│               │   │   │   │   │   ├── expect.dev
│               │   │   │   │   │   └── service.dev.properties
│               │   │   │   │   ├── ic3/
│               │   │   │   │   │   ├── expect.dev
│               │   │   │   │   │   ├── expect.dev2
│               │   │   │   │   │   ├── service.dev.properties
│               │   │   │   │   │   └── service.dev2.properties
│               │   │   │   │   ├── ic4/
│               │   │   │   │   │   ├── expect.dev
│               │   │   │   │   │   ├── service.dev.properties
│               │   │   │   │   │   └── service.dev2.properties
│               │   │   │   │   └── ic5/
│               │   │   │   │       ├── expect.dev
│               │   │   │   │       └── service.properties
│               │   │   │   └── simpleInclude/
│               │   │   │       ├── si1/
│               │   │   │       │   ├── expect.uat
│               │   │   │       │   └── service.properties
│               │   │   │       ├── si2/
│               │   │   │       │   ├── expect.uat
│               │   │   │       │   └── service.properties
│               │   │   │       └── si3/
│               │   │   │           ├── expect.uat
│               │   │   │           └── service.properties
│               │   │   ├── linksFromProfiles/
│               │   │   │   ├── includeFromProfile/
│               │   │   │   │   ├── application.profile.yaml
│               │   │   │   │   └── expect.env
│               │   │   │   ├── placeholderFromProfile/
│               │   │   │   │   ├── application.profile.yaml
│               │   │   │   │   └── expect.env
│               │   │   │   └── targetForProfile/
│               │   │   │       ├── application.env.yaml
│               │   │   │       ├── application.profile.yaml
│               │   │   │       ├── expect.env
│               │   │   │       └── expect.profile
│               │   │   ├── mergeLists/
│               │   │   │   ├── application.yaml
│               │   │   │   └── expect.env
│               │   │   ├── multiVar/
│               │   │   │   ├── application.prod.yaml
│               │   │   │   ├── application.yaml
│               │   │   │   └── expect.prod
│               │   │   ├── other/
│               │   │   │   ├── common/
│               │   │   │   │   ├── expect.dev
│               │   │   │   │   └── oracle.properties
│               │   │   │   ├── th/
│               │   │   │   │   ├── nonexists/
│               │   │   │   │   │   └── service.properties
│               │   │   │   │   ├── th-client/
│               │   │   │   │   │   ├── java.proc
│               │   │   │   │   │   ├── service.properties
│               │   │   │   │   │   └── service.uat.properties
│               │   │   │   │   └── th-server/
│               │   │   │   │       ├── arg.proc
│               │   │   │   │       ├── service.demo.properties
│               │   │   │   │       ├── service.properties
│               │   │   │   │       └── service.uat.properties
│               │   │   │   └── zeus/
│               │   │   │       ├── expect.demo
│               │   │   │       ├── expect.some
│               │   │   │       ├── expect.uat
│               │   │   │       ├── service.demo.properties
│               │   │   │       ├── service.properties
│               │   │   │       └── service.uat.properties
│               │   │   ├── placeholderAsDefaultValue/
│               │   │   │   ├── appication.yaml
│               │   │   │   └── expect.placeholderAsDefaultValue
│               │   │   ├── placeholderOverride/
│               │   │   │   ├── placeholderOverride1/
│               │   │   │   │   ├── appication.yaml
│               │   │   │   │   └── expect.dev
│               │   │   │   └── placeholderOverride2/
│               │   │   │       ├── appication.dev2.yaml
│               │   │   │       ├── appication.yaml
│               │   │   │       └── expect.dev
│               │   │   ├── placeholderToMap/
│               │   │   │   ├── 2expect.nextLevel
│               │   │   │   ├── 2expect.sameLevel
│               │   │   │   ├── appication.nextLevel.yaml
│               │   │   │   └── appication.sameLevel.yaml
│               │   │   ├── placeholderToSpel/
│               │   │   │   ├── pts/
│               │   │   │   │   ├── expect.dev
│               │   │   │   │   └── service.properties
│               │   │   │   └── ptsports/
│               │   │   │       ├── expect.dev
│               │   │   │       └── service.properties
│               │   │   ├── portOffsetTest/
│               │   │   │   ├── expect.dev
│               │   │   │   ├── expect.dev2
│               │   │   │   └── service.properties
│               │   │   ├── predefinedFunctions/
│               │   │   │   ├── application.yaml
│               │   │   │   └── expect.dev
│               │   │   ├── profiles/
│               │   │   │   └── profileAndInclude/
│               │   │   │       ├── p_common/
│               │   │   │       │   └── application.yaml
│               │   │   │       ├── p_service/
│               │   │   │       │   ├── application.yaml
│               │   │   │       │   ├── expect.dev_with_profile
│               │   │   │       │   └── expect.test
│               │   │   │       └── p_vars/
│               │   │   │           ├── application.dev_with_profile.yaml
│               │   │   │           ├── application.some.yaml
│               │   │   │           └── application.yaml
│               │   │   ├── selfPlaceholderOverride/
│               │   │   │   ├── scomp1/
│               │   │   │   │   ├── expect.dev
│               │   │   │   │   └── service.properties
│               │   │   │   └── scomp2/
│               │   │   │       ├── expect.dev
│               │   │   │       └── service.properties
│               │   │   ├── similarEnvNamesTest/
│               │   │   │   ├── dependent/
│               │   │   │   │   ├── expect.another-dev
│               │   │   │   │   ├── expect.dev
│               │   │   │   │   ├── expect.some
│               │   │   │   │   ├── expect.z-dev
│               │   │   │   │   ├── service.another-dev.properties
│               │   │   │   │   ├── service.dev.properties
│               │   │   │   │   ├── service.properties
│               │   │   │   │   └── service.z-dev.properties
│               │   │   │   └── main/
│               │   │   │       ├── expect.another-dev
│               │   │   │       ├── expect.dev
│               │   │   │       ├── expect.some
│               │   │   │       ├── expect.z-dev
│               │   │   │       └── service.properties
│               │   │   ├── simple/
│               │   │   │   ├── application.yaml
│               │   │   │   ├── expect.dev
│               │   │   │   └── simple2/
│               │   │   │       └── application.yaml
│               │   │   ├── specialPlaceholders/
│               │   │   │   ├── application.properties
│               │   │   │   ├── expect.special
│               │   │   │   └── expect.special.specialPlaceholders2
│               │   │   ├── spelWrap/
│               │   │   │   ├── expect.dev
│               │   │   │   └── service.properties
│               │   │   ├── thisOverride/
│               │   │   │   ├── tov1/
│               │   │   │   │   ├── expect.uat
│               │   │   │   │   └── service.properties
│               │   │   │   └── tov2/
│               │   │   │       ├── expect.uat
│               │   │   │       └── service.properties
│               │   │   ├── var/
│               │   │   │   ├── expect.dev
│               │   │   │   └── var.properties
│               │   │   ├── yamlLists/
│               │   │   │   ├── application.yaml
│               │   │   │   └── expect.env
│               │   │   └── yamlMultiline/
│               │   │       ├── application.yaml
│               │   │       └── expect.dev
│               │   └── envs/
│               │       ├── abstract.yaml
│               │       ├── aliases.yaml
│               │       ├── bad/
│               │       │   ├── notUniqueComponents.yaml
│               │       │   └── parseError.yaml
│               │       ├── dev.yaml
│               │       ├── dev2.json
│               │       ├── dev_with_profile.yaml
│               │       ├── env.yaml
│               │       ├── p1.json
│               │       ├── prod-a.yaml
│               │       ├── prod-b.yaml
│               │       ├── profs.yaml
│               │       ├── special.yaml
│               │       ├── uat.json
│               │       └── var.json
│               └── templates/
│                   ├── components/
│                   │   └── mustache/
│                   │       ├── application.yaml
│                   │       ├── expect.dev
│                   │       └── template.templ
│                   ├── envs/
│                   │   └── dev.yaml
│                   └── templateWithMultiLines.yaml
├── pomSettings.gradle
├── release.sh
├── secring.gpg.gpg
├── settings.gradle
└── utils/
    └── src/
        ├── main/
        │   └── java/
        │       └── io/
        │           └── microconfig/
        │               ├── io/
        │               │   ├── DumpedFsReader.java
        │               │   └── FsReader.java
        │               └── utils/
        │                   ├── CacheProxy.java
        │                   ├── CollectionUtils.java
        │                   ├── ConsoleColor.java
        │                   ├── FileUtils.java
        │                   ├── IoUtils.java
        │                   ├── Logger.java
        │                   ├── Os.java
        │                   ├── StreamUtils.java
        │                   └── StringUtils.java
        └── test/
            ├── java/
            │   └── io/
            │       └── microconfig/
            │           ├── io/
            │           │   └── DumpedFsReaderTest.java
            │           └── utils/
            │               ├── CacheProxyTest.java
            │               ├── CollectionUtilsTest.java
            │               ├── ConsoleColorTest.java
            │               ├── FileUtilsTest.java
            │               ├── IoUtilsTest.java
            │               ├── StreamUtilsTest.java
            │               └── StringUtilsTest.java
            └── resources/
                └── file.yaml

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/scripts/decrypt_secring.sh
================================================
#!/bin/sh

mkdir $HOME/secrets
# --batch to prevent interactive command --yes to assume "yes" for questions
gpg --quiet --batch --yes --decrypt --passphrase="$SECRET_PASSPHRASE" \
--output $HOME/secrets/secring.pgp secring.gpg.gpg

================================================
FILE: .github/scripts/native/Dockerfile-alpine
================================================
FROM ghcr.io/graalvm/native-image:muslib-22 AS builder

WORKDIR /

ADD microconfig.jar /microconfig.jar
RUN native-image --static --libc=musl -jar /microconfig.jar
RUN /microconfig -v

ENTRYPOINT cp /microconfig /volume/microconfig

================================================
FILE: .github/scripts/native/graalvm-linux.sh
================================================
curl -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_linux-x64_bin.tar.gz -o graalvm.tar.gz
mkdir .graalvm
tar -xf graalvm.tar.gz -C .graalvm
rm graalvm.tar.gz
mv .graalvm/graalvm-community-openjdk-*/* .graalvm/
rm -rf .graalvm/graalvm-community-openjdk-*
.graalvm/bin/native-image --version

================================================
FILE: .github/scripts/native/graalvm-mac.sh
================================================
curl -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_macos-x64_bin.tar.gz -o graalvm.tar.gz
mkdir .graalvm
tar -xf graalvm.tar.gz -C .graalvm
rm graalvm.tar.gz
mv .graalvm/graalvm-community-openjdk-*/Contents/Home/* .graalvm/
rm -rf .graalvm/graalvm-community-openjdk-*
.graalvm/bin/native-image --version

================================================
FILE: .github/scripts/native/graalvm-win.sh
================================================
curl -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_windows-x64_bin.zip -o graalvm.zip
unzip -q graalvm.zip -d graalvm
rm graalvm.zip
mv graalvm/graalvm-community-openjdk-*/* graalvm/
rm -rf graalvm/graalvm-community-openjdk-*
graalvm/bin/native-image.cmd --version

================================================
FILE: .github/scripts/native/native.bat
================================================
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
graalvm\bin\native-image.cmd -jar microconfig.jar

================================================
FILE: .github/scripts/native/native.sh
================================================
ls -lh
.graalvm/bin/native-image -jar microconfig.jar

================================================
FILE: .github/scripts/set_gradle_properties.sh
================================================
sed "s+$1=+$1=$2+g" gradle.properties > gradle.properties.tmp && mv gradle.properties.tmp gradle.properties


================================================
FILE: .github/workflows/build.yml
================================================
name: Multi OS Build

on:
  push:
    branches: [ master ]

jobs:
  build:
    runs-on: ${{matrix.os}}
    strategy:
      matrix:
        os:
         - ubuntu-latest
         - windows-latest
           
    steps:
    - uses: actions/checkout@v2
    - name: Set up JDK
      uses: actions/setup-java@v1
      with:
        java-version: 17
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
    - name: Build with Gradle
      run: ./gradlew build --info


================================================
FILE: .github/workflows/gradlepublish.yml
================================================
name: Publish to Maven Central Staging

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK
        uses: actions/setup-java@v1
        with:
          java-version: 17
          server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
          settings-path: ${{ github.workspace }} # location for the settings.xml file

      - name: Build with Gradle
        run: ./gradlew build

      - name: Decrypt secring
        run: ./.github/scripts/decrypt_secring.sh
        env:
          SECRET_PASSPHRASE: ${{ secrets.SECRET_PASSPHRASE }}

      - name: Fill gradle properties
        run: |
          ./.github/scripts/set_gradle_properties.sh ossrhUsername ${{ secrets.SONATYPE_USERNAME }}
          ./.github/scripts/set_gradle_properties.sh ossrhPassword '${{ secrets.SONATYPE_PASSWORD }}'
          ./.github/scripts/set_gradle_properties.sh signing.keyId ${{ secrets.SIGNING_KEYID }}
          ./.github/scripts/set_gradle_properties.sh signing.password ${{ secrets.SIGNING_PASSWORD }}
          ./.github/scripts/set_gradle_properties.sh signing.secretKeyRingFile $HOME/secrets/secring.pgp

      - name: Publish to Maven Central Staging repository
        run: |
          ./gradlew :microconfig-core:publishNexusPublicationToMavenRepository
          ./gradlew :microconfig-api:publishNexusPublicationToMavenRepository
          ./gradlew :microconfig-cli:publishNexusPublicationToMavenRepository
          ./gradlew :utils:publishNexusPublicationToMavenRepository
          ./gradlew :microconfig-cli:publishShadowPublicationToMavenRepository


================================================
FILE: .github/workflows/release.yml
================================================
name: "Build Release"

on:
  push:
    tags:
      - 'v*'

jobs:
  build:
    runs-on: ubuntu-latest
    name: "Build Jar"
    steps:
      - name: checkout
        uses: actions/checkout@v2
      - name: Set up JDK
        uses: actions/setup-java@v1
        with:
          java-version: 17
      - name: Build Jar
        run: ./gradlew shadowJar
      - name: Rename Jar
        shell: bash
        run: mv microconfig-cli/build/libs/microconfig-cli-*-all.jar microconfig-cli/build/libs/microconfig.jar
      - uses: actions/upload-artifact@v4
        with:
          name: microconfig.jar
          path: microconfig-cli/build/libs/microconfig.jar
  alpine:
    name: "Build Alpine"
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v2
      - name: Download Jar
        uses: actions/download-artifact@v4.1.7
        with:
          name: microconfig.jar
      - name: Build Binary
        shell: bash
        run: |
          mkdir volume
          docker build -t microconfig:alpine -f .github/scripts/native/Dockerfile-alpine .
          docker run -v "$PWD/volume":/volume microconfig:alpine
      - uses: actions/upload-artifact@v4
        with:
          name: microconfig-alpine
          path: volume/microconfig
  linux:
    name: "Build Linux"
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v2
      - name: Download Jar
        uses: actions/download-artifact@v4.1.7
        with:
          name: microconfig.jar
      - name: Install GraalVM Native Image
        shell: bash
        run: .github/scripts/native/graalvm-linux.sh
      - name: Build Binary
        shell: bash
        run: .github/scripts/native/native.sh
      - uses: actions/upload-artifact@v4
        with:
          name: microconfig-linux
          path: ./microconfig

  windows:
    name: "Build Windows"
    needs: build
    runs-on: windows-2022
    steps:
      - name: checkout
        uses: actions/checkout@v2
      - name: Download Jar
        uses: actions/download-artifact@v4.1.7
        with:
          name: microconfig.jar
      - name: Install GraalVM Native Image
        shell: bash
        run: .github/scripts/native/graalvm-win.sh
      - name: Build Binary
        shell: bash
        run: .github/scripts/native/native.bat
      - uses: actions/upload-artifact@v4
        with:
          name: microconfig-windows
          path: microconfig.exe

  macos:
    name: "Build MacOS"
    needs: build
    runs-on: macos-latest
    steps:
      - name: checkout
        uses: actions/checkout@v2
      - name: Download Jar
        uses: actions/download-artifact@v4.1.7
        with:
          name: microconfig.jar
      - name: Install GraalVM Native Image
        shell: bash
        run: .github/scripts/native/graalvm-mac.sh
      - name: Build Binary
        shell: bash
        run: .github/scripts/native/native.sh
      - uses: actions/upload-artifact@v4
        with:
          name: microconfig-macos
          path: ./microconfig

  release:
    name: "Create release"
    needs: [linux, macos, windows, alpine]
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Grab Version
        env:
          ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
        shell: bash
        run: version=$(head -1 gradle.properties); echo "::set-env name=version::${version/*=}"
      - name: Create Release
        id: create_release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
        with:
          tag_name: v${{ env.version }}
          release_name: ${{ env.version }}
          draft: true
          prerelease: false

      - name: Download Jar
        uses: actions/download-artifact@v4.1.7
        with:
          name: microconfig.jar
      - name: Upload Jar Release
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: microconfig.jar
          asset_name: microconfig.jar
          asset_content_type: application/java-archive

      - name: Download Binary
        uses: actions/download-artifact@v4.1.7
        with:
          name: microconfig-alpine
      - name: Zip
        shell: bash
        run: zip -m microconfig-alpine.zip microconfig
      - name: Upload Release Artifact
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: microconfig-alpine.zip
          asset_name: microconfig-alpine.zip
          asset_content_type: application/zip

      - name: Download Binary
        uses: actions/download-artifact@v4.1.7
        with:
          name: microconfig-linux
      - name: Zip
        shell: bash
        run: zip -m microconfig-linux.zip microconfig
      - name: Upload Release Artifact
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: microconfig-linux.zip
          asset_name: microconfig-linux.zip
          asset_content_type: application/zip

      - name: Download Binary
        uses: actions/download-artifact@v4.1.7
        with:
          name: microconfig-macos
      - name: Zip
        shell: bash
        run: zip -m microconfig-macos.zip microconfig
      - name: Upload Release Artifact
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: microconfig-macos.zip
          asset_name: microconfig-macos.zip
          asset_content_type: application/zip

      - name: Download Binary
        uses: actions/download-artifact@v4.1.7
        with:
          name: microconfig-windows
      - name: Zip
        shell: bash
        run: zip -m microconfig-windows.zip microconfig.exe
      - name: Upload Release Artifact
        id: upload-release-asset
        uses: actions/upload-release-asset@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: microconfig-windows.zip
          asset_name: microconfig-windows.zip
          asset_content_type: application/zip


================================================
FILE: .gitignore
================================================
*.ipr
*.iml
*.iws
.idea/
.bash_history
.bash_logout
.bash_profile
.bashrc
.emacs
.lesshst
.ssh/
.viminfo
.vimrc
.project
target/
build/
.gradle/
.graalvm/
classes/
out/

microconfig.jar
microconfig.exe

================================================
FILE: .travis.yml
================================================
language: java
dist: trusty
jdk: openjdk9

addons:
  sonarcloud:
    organization: "microconfig"
    token: 73371217f9b049ece1f4ba72f70212e6fcdbaa52

script:
  - ./gradlew check --info
  - ./gradlew jacocoTestReport --info
  - ./gradlew sonarqube --info

================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# Quick start

[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.microconfig/microconfig-core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.microconfig/microconfig-core)
[![Slack badge](https://img.shields.io/badge/Join-Slack-brightgreen.svg)](https://join.slack.com/t/microconfig/shared_invite/zt-dflf2m0n-wOPVfAmk5eiHPn_9Omff7Q)

We recommend to start with [Microconfig Features guide](https://microconfig.io/features.html#/) and then continue reading this documentation.


# Microconfig overview and features

Microconfig is intended to make it easy and convenient to manage configuration for microservices (or just for a big amount of services) and reuse the common part.

If your project consists of tens or hundreds of services you have to:

* Keep the configuration for each service ideally separate from the code.
* The configuration for different services can have common and specific parts. Also, the configuration for the same service in different environments can have common and specific parts.
* A common part for different services (or for one service in different environments) should not be copied and pasted and must be easy to reuse.
* It must be easy to understand how the resulting configuration is generated and based on which values the config placeholders are resolved.
* Some configuration properties must be dynamic, calculated using an expression language.

Microconfig is written in Java, but it's designed to be used with systems written in any language. Microconfig just describes a format of configuration sources, syntax for placeholders, includes, excludes, overrides, an expression language for dynamic properties and an engine that can transform the config sources into simple *.yaml or *.properties files. Also it can resolve placeholders in arbitrary template files and show differences between config releases.

## The difference between Microconfig and popular DevOps tools
**Compared to config servers** (like Consul, Zookeeper, Spring Cloud Config):

Config servers solve the problem of dynamic distribution of configuration in runtime (can use http endpoints), but to distribute configuration you have to store it, ideally with changes in history and without duplication of common parts.

**Compared to Ansible**:

Ansible is a powerful, but much too general, engine for deployment management and doesn't provide a common and clean way to store configuration for microservices, and a lot of teams have to invent their own solutions based on Ansible.

Microconfig does one thing and does it well. It provides an approach, best practices for how to keep configuration for a big amount of services, and an engine to build config sources into result files.

You can use Microconfig together with any config servers and deployment frameworks. Configuration can be built during the deployment phase and the resulting plain config files can be copied to the filesystem, where your services can access them directly (for instance, Spring Boot can read configuration from *.yaml or *.properties), or you can distribute the resulting configuration using any config servers. Also, you can store not only application configuration but configuration used to run your services, and your deployment framework can read that configuration from Microconfig to start your services with the right parameters and settings.

## Where to store the configuration
It’s a good practice to keep service configuration separate from code. It doesn't require you to rebuild services every time the configuration is changed and allows you to use the same service artefacts (for instance, *.jar) for all environments because it doesn’t contain any environment specific configuration. The configuration can be updated even in runtime without service source code changes.

The best way to follow this principle is to have a dedicated repository for configuration in your favorite version control system.  You can store configuration for all microservices in the same repository to make it easy to reuse a common part and be sure the common part is consistent for all your services.

## Service configuration types

It's convenient to have different kinds of configuration and keep it in different files:
* Deploy configuration (the configuration used by deployment tools that describes where/how to deploy your service, like artifact repository settings, container params).
* Process configuration (the configuration used by deployment tools to start your service with right params, like memory limits, VM params, etc.).
* Application configuration (the configuration that your service reads after start-up and uses in runtime).
* Environment variables.
* Secret configuration (note, you should not store in a VCS any sensitive information, like passwords. In a VCS you can store references(keys) to passwords, and keep passwords in special secured stores(like Vault) or at least in encrypted files on environment machines).
* Library specific templates (for instance, Dockerfile, kafka.conf, cassandra.yaml, some scripts to run before/after your service start-up, etc.)

Microconfig detects the configuration type by the config file extension. The default configuration for config types:
* `*.yaml` or `*.properties` for application configuration.
* `*.deploy` for deployment configuration.
* `*.k8s` for k8s configuration.
* `*.proc` or `*.process` for process configuration. 
* `*.helm` for helm values.
* `*.env` for environment variables.
* `*.secret` for secret configuration.
* For static files - see the 'Templates files' section.

You can use all the configuration types or only some of them. Also you can override the default extensions or define your own config types.

# Basic folder layout
Let’s take a look at a basic folder layout that you can keep in a dedicated repository.

For every service, you have to create a folder with a unique name(the name of the service). In the service directory, we will keep common and environment specific configurations.

So, let’s imagine we have 4 microservices: 'orders', 'payments', 'service-discovery', and 'api-gateway'. For convenience, we can group services by layers: 'infra' for infrastructure services and 'core' for our business domain services. The resulting layout will look like:

```
repo
└───core  
│   └───orders
│   └───payments
│	
└───infra
    └───service-discovery
    └───api-gateway
```

## Configuration sources

Inside the service folder, you can create a configuration in `key=value` format. For the following examples, we will prefer using *.yaml, but Microconfig also supports *.properties. 

Let’s create the basic application and process configuration files for each service.
You can split configuration among several files, but for simplicity, we will create `application.yaml` and `process.proc` for each service. No matter how many base files are used, after the configuration build for each service and each config type, a single result file will be generated.

```
repo
└───core  
│    └───orders
│    │   └───application.yaml
│    │   └───process.proc
│    └───payments
│        └───application.yaml
│        └───process.proc
│	
└───infra
    └───service-discovery
    │   └───application.yaml
    │   └───process.proc
    └───api-gateway
        └───application.yaml
        └───process.proc
```

Inside process.proc we will store configuration that describes what your service is, and how to run it (your config files can have other properties, so don't pay attention to concrete values).

**orders/process.proc**
```properties
artifact=org.example:orders:19.4.2 # partial duplication
java.main=org.example.orders.OrdersStarter
java.opts.mem=-Xms1024M -Xmx2048M -XX:+UseG1GC -XX:+PrintGCDetails -Xloggc:logs/gc.log # duplication
```
**payments/process.proc**
```properties
artifact=org.example:payments:19.4.2 # partial duplication
java.main=org.example.payments.PaymentStarter
java.opts.mem=-Xms1024M -Xmx2048M -XX:+UseG1GC -XX:+PrintGCDetails -Xloggc:logs/gc.log # duplication
instance.count=2
```
**service-discovery/process.proc**
```properties
artifact=org.example.discovery:eureka:19.4.2 # partial duplication 
java.main=org.example.discovery.EurekaStarter
java.opts.mem=-Xms1024M -Xmx2048M # partial duplication 
```

As you can see we already have some small duplication (all services have '19.4.2' version, and two of them have the same java.ops params).  Configuration duplication is as bad as code duplication. We will see later how to do this in a better way.

Let's see what application properties look like. In the comments we note what can be improved.

**orders/application.yaml**
```yaml
server.port: 9000
application.name: orders # better to get name from folder
orders.personalRecommendation: true
statistics.enableExtendedStatistics: true
service-discovery.url: http://10.12.172.11:6781 # are you sure url is consistent with SD configuration?
eureka.instance.prefer-ip-address: true  # duplication
datasource:
  minimum-pool-size: 2  # duplication
  maximum-pool-size: 10
  url: jdbc:oracle:thin:@172.30.162.31:1521:ARMSDEV  # partial duplication
jpa.properties.hibernate.id.optimizer.pooled.prefer_lo: true  # duplication
```
**payments/application.yaml**
```yaml
server.port: 8080
application.name: payments # better to get name from folder
payments:
  bookTimeoutInMs: 900000 # difficult to read. How long in minutes?
  system.retries: 3
consistency.validateConsistencyIntervalInMs: 420000 # difficult to read. How long in minutes?
service-discovery.url: http://10.12.172.11:6781 # are you sure url is consistent with eureka configuration?
eureka.instance.prefer-ip-address: true  # duplication
datasource:
  minimum-pool-size: 2  # duplication
  maximum-pool-size: 5
datasource.url: jdbc:oracle:thin:@172.30.162.127:1521:ARMSDEV  # partial duplication
jpa.properties.hibernate.id.optimizer.pooled.prefer_lo: true # duplication
```
**service-discovery/application.yaml**
```yaml
server.port: 6781
application.name: eureka
eureka:
  client.fetchRegistry: false
  server:
    eviction-interval-timer-in-ms: 15000 # difficult to read
    enable-self-preservation: false    
```

The first bad thing - application files contain duplication. 
Also, you have to spend some time to understand the application’s dependencies or its structure. 
For instance, payment-service contains settings for:
* service-discovery client
* oracle db 
* application specific 

Of course, you can separate a group of settings by an empty line. But we can make it more readable and understandable.

# Better config structure using #include
Our services have a common configuration for service-discovery and database. To make it easy to understand the service's dependencies, let’s create folders for service-discovery-client and oracle-client and specify links to these dependencies from the core services.

```
repo
└───common
|   └───service-discovery-client 
|   |   └───application.yaml
|   └───oracle-client
|       └───application.yaml
|	
└───core  
│   └───orders
│   │   ***
│   └───payments
│       ***
│	
└───infra
    └───service-discovery
    │   ***
    └───api-gateway
        ***
```
**service-discovery-client/application.yaml**
```yaml
service-discovery.url: http://10.12.172.11:6781 # are you sure url is consistent with eureka configuration?
eureka.instance.prefer-ip-address: true 
```

**oracle-client/application.yaml**
```yaml
datasource:
  minimum-pool-size: 2  
  maximum-pool-size: 5
  url: jdbc:oracle:thin:@172.30.162.31:1521:ARMSDEV  
jpa.properties.hibernate.id.optimizer.pooled.prefer_lo: true
```

And replace explicit configs with includes

**orders/application.yaml**
```yaml
#include service-discovery-client, oracle-db-client

server.port: 9000
application.name: orders # better to get name from folder
orders.personalRecommendation: true
statistics.enableExtendedStatistics: true
```

**payments/application.yaml**
```yaml
#include service-discovery-client, oracle-db-client

server.port: 8080
application.name: payments # better to get name from folder
consistency.validateConsistencyIntervalInMs: 420000 # difficult to read. How long in minutes?
payments:
  bookTimeoutInMs: 900000 # how long in minutes?
  system.retries: 3
```
To include a component's configuration you need to specify only the component name, you don't need to specify its path. This makes the config layout refactoring easier. Microconfig will find a folder with the component's name and include the configuration from its files (if the folder name is not unique, Microconfig includes configs from each folder, but it's a good idea to keep a component name unique).

Some problems still here, but we removed the duplication and made it easier to understand the service's dependencies.

You can override any properties from your dependencies.
Let's override the order's connection pool size.

**orders/application.yaml**
```yaml    
#include oracle-db-client

datasource.maximum-pool-size: 10
***
```

Nice. But order-service has a small part of its db configuration(pool-size), it's not that bad, but we can make the config semantically better.
Also you can see that order and payment services have a different ip for oracle.

order: datasource.url: jdbc:oracle:thin:@172.30.162.<b>31</b>:1521:ARMSDEV  
payment: datasource.url: jdbc:oracle:thin:@172.30.162.<b>127</b>:1521:ARMSDEV  
And oracle-client contains settings for .31.

Of course, you can override datasource.url in the payment/application.yaml. But this overridden property will contain a copy of another part of jdbc url and you will get all the standard 'copy-and-paste' problems. We would like to override only a part of the property. 

Also it's better to create a dedicated configuration for order db and payment db. Both db configuration will include common-db config and override the 'ip' part of url. After that, we will migrate 'datasource.maximum-pool-size' from order-service to order-db, so order-service will contain only links to its dependencies and service-specific configs.

Let’s refactor.
```
repo
└───common
|   └───oracle
|       └───oracle-common
|       |   └───application.yaml
|       └───order-db
|       |   └───application.yaml
|       └───payment-db
|           └───application.yaml
```

**oracle-common/application.yaml**
```yaml
datasource:
  minimum-pool-size: 2  
  maximum-pool-size: 5    
connection.timeoutInMs: 300000
jpa.properties.hibernate.id.optimizer.pooled.prefer_lo: true
```
**orders-db/application.yaml**
```yaml
#include oracle-common
    
datasource:
  maximum-pool-size: 10
  url: jdbc:oracle:thin:@172.30.162.31:1521:ARMSDEV #partial duplication
```
**payment-db/application.yaml**
```yaml
#include oracle-common
    
datasource.url: jdbc:oracle:thin:@172.30.162.127:1521:ARMSDEV #partial duplication
```

**orders/application.yaml**
```yaml
#include order-db
***
```

**payments/application.yaml**
```yaml
#include payment-db
```

Includes can be in one line or on different lines:

```yaml
#include service-discovery-client
#include oracle-db-client, monitoring    
```

# Placeholders

Instead of duplicating the value of some properties, Microconfig allows you to have a link (placeholder) to this value. 

Let's refactor the service-discovery-client config.

Initial:

**service-discovery-client/application.yaml**
```yaml
service-discovery.url: http://10.12.172.11:6781 # are you sure host and port are consistent with SD configuration? 
```
**service-discovery/application.yaml**
```yaml
server.port: 6761 
```

Refactored:

**service-discovery-client/application.yaml**
```yaml
service-discovery.url: http://${service-discovery@ip}:${service-discovery@server.port}
```
**service-discovery/application.yaml**
```yaml
server.port: 6761
ip: 10.12.172.11 
```
So if you change the service-discovery port, all dependent services will get this update.

Microconfig has another approach to store service's ip. We will discuss it later. For now, it's better to set the 'ip' property in the service-discovery config file. 

The Microconfig syntax for placeholders: `${componentName@propertyName}`. Microconfig forces you to specify the component name. This syntax is better than just a property name
(like `${connectionSize}`), because it makes it obvious where to find the original placeholder value.

Let's refactor oracle db config using placeholders and environment specific overrides.

Initial:

**oracle-common/application.yaml**
```yaml    
datasource:
  maximum-pool-size: 10
  url: jdbc:oracle:thin:@172.30.162.31:1521:ARMSDEV 
```   

Refactored:

**oracle-common/application.yaml**
```yaml
datasource:
  maximum-pool-size: 10
  url: jdbc:oracle:thin:@${this@oracle.host}:1521:${this@oracle.sid}
oracle:
  host: 172.30.162.20
  sid: ARMSDEV
```
**oracle-common/application.uat.yaml**
```yaml
oracle.host: 172.30.162.80
```

**oracle-common/application.prod.yaml**
```yaml
oracle:
  host: 10.17.14.18
  sid: ARMSPROD
```

As you can see using placeholders we can override not only the whole property but also part of it.

A placeholder can link to another placeholder. Microconfig can resolve them recursively and detect cyclic dependencies.

## Temp properties

If you want to declare temp properties that will be used by placeholders only and you don't want them to be included in the result config file, you can declare them with `#var` keyword.

**oracle-common/application.yaml**
```yaml
datasource.url: jdbc:oracle:thin:@${this@oracle.host}:1521:${this@oracle.sid}
#var oracle.host: 172.30.162.20
#var oracle.sid: ARMSDEV
```
**oracle-common/application.uat.yaml**
```yaml
#var oracle.host: 172.30.162.80
``` 

This approach works with includes as well. You can #include oracle-common and then override 'oracle.host', and 'datasource.url' will be resolved based on the overridden value.

In the example below after the build process: datasource.url: jdbc:oracle:thin:@**100.30.162.80**:1521:ARMSDEV

 
**orders-db/application.dev.yaml** 
```yaml   
#include oracle-common
 
#var oracle.host: 100.30.162.80         
```
## Removing base properties
Using `#var` you can remove properties from the result config file. You can include some config and override any property with #var to exclude it from the result config file.

Let's remove 'payments.system.retries' property for 'dev' environment:

**db-client/application.yaml**
```yaml
datasource:
  minimum-pool-size: 2  
  maximum-pool-size: 5
```
**payments/application.yaml**
```yaml
#include db-client
#var datasource.minimum-pool-size:  // will not be included into result config       
```

## Placeholder's default value
You can specify a default value for a placeholder using the following syntax: ${component@property:**defaultValue**}

Let's set a default value for 'oracle host'

**oracle-common/application.yaml**
```yaml
datasource:
  maximum-pool-size: 10
  url: jdbc:oracle:thin:@${this@oracle.host:172.30.162.20}:1521:${this@oracle.sid}
#var oracle.sid: ARMSDEV
```
Note, a default value can be a placeholder:
 `${component@property:${component2@property7:Missing value}}`
 
In the example Microconfig will try to:
* resolve `${component@property}`
* if the above is missing - resolve `${component2@property7}`
* if the above is missing - return 'Missing value'

If a placeholder doesn't have a default value and that placeholder can't be resolved, Microconfig throws an exception with the detailed problem description.

## Specials placeholders
As we discussed the syntax for placeholders looks like `${component@property}`.
Microconfig has several special useful placeholders:

* `${this@env}` - returns the current environment name.
* `${...@name}` - returns the component's name.
* `${...@configDir}` - returns the full path of the component's config dir.
* `${...@resultDir}` - returns the full path of the component's destination dir (the resulting files will be put into this dir).
* `${this@configRoot}` - returns the full path of the config repository root dir (see `root` build param ).

There are some other environment descriptor related properties, we will discuss them later:
* `${...@ip}`
* `${...@portOffset}`
* `${...@group}`
* `${...@order}`

Note, if you use a special placeholder with `${this@...}` then the value will be context dependent. Let's apply `${this@name}` to see why it's useful.

Initial:

**orders/application.yaml**
```yaml
#include service-discovery-client

application.name: orders
```
**payments/application.yaml**
```yaml
#include service-discovery-client

application.name: payments
```

Refactored:

**orders/application.yaml**
```yaml
#include service-discovery-client
```
**payments/application.yaml**
```yaml
#include service-discovery-client
```
**service-discovery-client/application.yaml**
```yaml
application.name: ${this@name}
``` 

## Environment variables and system properties 
To resolve environment variables use the following syntax: `${env@variableName}`

For example:
```
 ${env@Path}
 ${env@JAVA_HOME}
 ${env@NUMBER_OF_PROCESSORS}
```

To resolve Java system variables (System::getProperty) use the following syntax: `${system@variableName}`

Some useful standard system variables:

```
 ${system@user.home}
 ${system@user.name}
 ${system@os.name}
```

You can pass your own system properties during Microconfig start with `-D` prefix (See 'Running config build' section)

Example:
```
 -DtaskId=3456 -DsomeParam3=value
```
Then you can access it: `${system@taskId}` or `${system@someParam3}`

## Placeholders to another config type

As we discussed Microconfig supports different config types and detects the type by file extensions. Microconfig resolves placeholders based on properties of the **same config type** only.

Let’s see the example how it works:

‘orders’ has ‘service.port’ property in application.**yaml**, so you can declare a placeholder to this property from application config types only (*.yaml or *.properties). If you declare that placeholder in, for example, *.process files, Microconfig will not resolve it and throw an exception.

**someComponent/application.yaml**
```yaml
orderPort: ${orders@server.port} # works
```
**someComponent/application.process**
```yaml
orderPort: ${orders@server.port} # doesn’t work
```

If you need to declare a placeholder to a property from another config type you have to specify the config type using the following syntax: ${**configType**::component@property}.

For our example the correct syntax:

**someComponent/application.process**
```yaml
orderPort: ${app::orders@server.port}
```

Microconfig default config types:
* `app` – for *.yaml or *.properties
* `process` – for *.proc or *.process
* `deploy` – for *.deploy
* `secret` – for *.secret
* `env` – for *.env

# Expression language
Microconfig supports math expressions, conditions and Java [String API](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html).

Let's see some examples:

```yaml
#Better than 300000
connection.timeoutInMs: #{5 * 60 * 1000}

#Microconfig placeholder and simple math
datasource.maximum-pool-size: #{${this@datasource.minimum-pool-size} + 10} 

#Using placeholder and Java String API
mainClassNameWithoutPackage: #{'${this@java.main}'.substring('${this@java.main}'.lastIndexOf('.') + 1)}

month: #{'${this@yyyy-MM-dd}'.split('-')[1]}

#Condition
releaseType: #{'${this@version}'.endsWith('-SNAPSHOT') ? 'snapshot' : 'release'}

```

# Environment specific properties
Microconfig allows specifying environment specific properties (add/remove/override). For instance, you want to increase the connection-pool-size for dbs and increase the amount of memory for prod env.
To add/remove/override properties for the environment, you can create application.**${ENVNAME}**.yaml file in the config folder. 

Let's override connection pool size for 'dev' and 'prod' and add one new param for 'dev'. 

```
order-db
└───application.yaml
└───application.dev.yaml
└───application.prod.yaml
```

**orders-db/application.dev.yaml**
```yaml   
datasource.maximum-pool-size: 15   
hibernate.show-sql: true
```

**orders-db/application.prod.yaml**
```yaml   
datasource.maximum-pool-size: 50
```

Also, you can declare common properties for several environments in a single file. You can use the following filename pattern: application.**${ENV1.ENV2.ENV3...}**.yaml

Let's create common properties for dev, dev2 and test environments.

```
order-db
└───application.yaml
└───application.dev.yaml
└───application.dev.dev2.test.yaml
└───application.prod.yaml
```

**orders-db/application.dev.dev2.test.yaml**
```yaml   
hibernate.show-sql: true
```

When you build config for a specific environment (for example 'dev') Microconfig will collect properties from:
* application.yaml 
* then add/override properties from application.dev.{anotherEnv}.yaml.
* then add/override properties from application.dev.yaml.
 
## Profiles and explicit environment names for includes and placeholders
As we discussed you can create environment specific properties using the filename pattern: application.${ENV}.yaml. You can use the same approach for creating profile specific properties.

For example, you can create a folder for http client timeout settings:

**timeout-settings/application.yaml**
```yaml
timeouts:
  connectTimeoutMs: 1000
  readTimeoutMs: 5000
```
And some services can include this configuration:

**orders/application.yaml**
```yaml
#include timeout-settings
```
**payments/application.yaml**
```yaml
#include timeout-settings
```

But what if you want some services to be configured with a long timeout? Instead of the environment you can use the profile name in the filename:
```
timeout-settings
└───application.yaml
└───application.long.yaml
└───application.huge.yaml
```
**timeout-settings/application.long.yaml**
```yaml
timeouts.readTimeoutMs: 30000
```
**timeout-settings/application.huge.yaml**
```yaml
timeouts.readTimeoutMs: 600000
```

And specify the profile name with include:

**payments/application.yaml**
```yaml
#include timeout-settings[long]
```

You can use the profile/environment name with placeholders as well:

```
${timeout-settings[long]@readTimeoutMs}
${kafka[test]@bootstrap-servers}
```

The difference between environment specific files and profiles is only logic. Microconfig handles it in the same way.

# Template files
Microconfig allows you to keep configuration files for any libraries in their specific format and resolve placeholders inside them.
For example, you want to keep logback.xml (or some other descriptor for your log library) and reuse this file with resolved placeholders for all your services. 

Let's create this file:
```
repo
└───common
|    └───logback-template 
|         └───logback.xml
```
**logback-template/logback.xml**
```xml
<configuration>
    <appender class="ch.qos.logback.core.FileAppender">
        <file>logs/${this@application.name}.log</file>
            <encoder>
                <pattern>%d [%thread] %highlight(%-5level) %cyan(%logger{15}) %msg %n</pattern>
            </encoder>
    </appender>    
</configuration>
```
So we want every service to have its own logback.xml with resolved `${application.name}`. 
Let's configure the order and payment services to use this template.

**orders/application.yaml**
```yaml
#include service-discovery-client

mc.template.logback.fromFile: ${logback@configDir}/logback.xml # full path to logback.xml, @configDir - special placeholder property
```

**payments/application.yaml**
```yaml
#include service-discovery-client

mc.template.logback.fromFile: ${logback@configDir}/logback.xml
```  
   
It's better to extract the common property `mc.template.logback.fromFile` to logback-template/application.yaml and then use #include.

```
repo
└───common
|   └───logback-template 
|   └───logback.xml
|   └───application.yaml
```    
**logback-template/application.yaml**
```yaml   
mc.template.logback.fromFile: ${logback@configDir}/logback.xml
```
**orders/application.yaml**
```yaml
#include service-discovery-client, logback-template
```
**payments/application.yaml**
```yaml
#include service-discovery-client, logback-template
```  

As we saw in the above text the order and payment services include the `application.name` property from service-discovery-client.
During the config build Microconfig will replace `${application.name}` inside logback.xml with the service's property value and copy the resulting file 'logback.xml' to the relevant folder for each service.

If you want to declare a property for a template only and don't want this property to be included into the result config file you can use `#var` keyword. 

If you want to override the template destination filename you can use `mc.template.${templateName}.toFile=${someFile}` property. For example:  
 
 **logback-template/application.yaml**
 ```yaml   
 mc.template.logback:
   fromFile: ${logback@configDir}/logback.xml
   toFile: logs/logback-descriptor.xml
 ``` 
 
You can use the absolute or the relative path for `toFile` property. The relative path starts from the resulting service config dir (see 'Running config build' section).

So the template dependency declaration syntax looks like:   
```
mc.template.${templateName}:
  fromFile: ${sourceTemplateFile}
  toFile: ${resolvedTemplateDestinationFile}
```
`${templateName}` - is used only for mapping `fromFile` and `toFile` properties.

Also, you can use a short one line syntax using ->
 ```
 mc.template.${templateName}: ${sourceTemplateFile} -> ${resolvedTemplateDestinationFile}
 ```
Using arrow notation you can also resolve directories with templates. This will resolve all files inside `${sourceTemplateDir}`. Source filename is used as target filename.
 ```
 mc.template.${templateName}: ${sourceTemplateDir}/* -> ${resolvedTemplateDestinationDir}
 ```
Or create multiple templates with different `${templateName}` from a single template file. 
Note the usage of `${templateName}` placeholder inside target filename to create different files based on template name.
 ```
 mc.template.[${templateName1},${templateName2}]: ${sourceTemplateFile} -> ${resolvedTemplateDestinationDir}/targetName-${templateName}.xml
 ```

Let's override the file that will be copied on the prod environment:
```
repo
└───common
|   └───logback-template 
|       └───logback.xml
|       └───logback-prod.xml
|       └───application.yaml
|       └───application.prod.yaml
```
**logback-template/application.prod.yaml**
```yaml   
mc.template.logback.fromFile: ${logback@configDir}/logback-prod.xml
``` 
## Mustache template engine support
If resolving placeholders inside templates is not enough for you, you can use [Mustache template engine](https://mustache.github.io/mustache.5.html). With Mustache you can use loops, conditions and includes.

Let's imagine we want to configure different Logback appenders on different environments. We can use condition 'appender.rolling' and override this value on different environments.

```
{{#appender.rolling}}
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>logs/${this@name}.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>logs/${this@name}.%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <maxFileSize>20MB</maxFileSize>
            <maxHistory>30</maxHistory>
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>
    </appender>
{{/appender.rolling}}
{{^appender.rolling}}
    <appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>logs/${this@name}.log</file>
    </appender>
{{/appender.rolling}}
```

 **logback-template/application.yaml**
 ```yaml   
mc.mustache.logback.fromFile: ${logback@configDir}/logback.xml
#var appender.rolling: true
 ``` 

 **logback-template/application.test.yaml**
 ```yaml   
#var appender.rolling: false
 ``` 

Microconfig uses Mustache if the template declaration starts with `mc.mustache` prefix:
```
mc.mustache.logback.fromFile: ${logback@configDir}/logback.xml
```
or the template file has  `*.mustache` extension:  
``` 
mc.template.logback:
  fromFile: ${logback@configDir}/logback.mustache
  toFile: logger.xml
```
or the short version
``` 
mc.template.logback: ${logback@configDir}/logback.mustache -> logger.xml
```
## Copy binary files
If you want to copy files as templates without placeholder resolving logic you can use the `mc.file.` prefix:
``` 
mc.file.someBinary: ${this@configDir}/cert.jks -> cert.jks
``` 
or
```
mc.file.someBinary:
  fromFile: ${this@configDir}/cert.jks
  toFile: cert.jks
```

# Environment descriptor
As we discussed every service can have default and environment-specific configurations, also we can extract a common configuration to some components. 
During the build phase we want to build configs for a subset of our components, only for real services on a concrete environment.
Of course, you can pass the environment name and the list of service names as parameters to build the configuration. But this is not very convenient if you want to build configuration for a large number of services.

So Microconfig allows specifying a list of service names on a special environment descriptor and then use only the environment name to build configs for all services listed on that descriptor.

Environments descriptors must be in `${configRoot}/envs` folder.
``` 
repo
└───components
|   └───***   
└───envs
    └───base.yaml
    └───dev.yaml
    └───test.yaml
    └───prod.yaml
```

Let's see the environment descriptor format:
 
 **envs/base.yaml**
```yaml
orders:  
  components:  
    - order-db-patcher
    - orders
    - order-ui

payments:
  components:
    - payment-db-patcher
    - payments
    - payment-ui

infra:
  components: 
    - service-discovery
    - api-gateway
    - ssl-api-gateway
    
monitoring:
  components:
    - grafana
    - prometheus    
```  

environment name = filename
```yaml
orders: # component group name
  components:  
    - order-db-patcher # component name(folder)
    - orders # component name
    - order-ui # component name
``` 

One environment can include another one and add/remove/override component groups:

**envs/test.yaml**
```yaml
include: # include all groups from 'base' environment except 'monitoring'
  env: base
  exclude:
   - monitoring

infra:
  exclude:
    - ssl-api-gateway # excluded ssl-api-gateway component from 'infra' group  
  append:
    - local-proxy # added new component into 'infra' group

tests_dashboard: # added new component group 'tests_dashboard'
  components:
    - test-statistic-collector
``` 

You can use the optional param `ip` for the environment or component groups and then use it via `${componentName@ip}`.

For instance, `${orders@ip}` will be resolved to 12.53.12.67, `${payment-ui@ip}` will be resolved to 170.53.12.80.   
```yaml
ip: 170.53.12.80 # default ip

orders:  
  ip: 12.53.12.67 # ip overridden for the group
  components:  
    - order-db-patcher
    - orders
    - order-ui

payments:  
  components:
    - payment-db-patcher
    - payments
    - payment-ui    
```

Consider configuring your deployment tool to read the environment descriptor to know which services to deploy.

## Environment profiles
You can use env profiles if you want to create a new env based on another env[s].
For example, you have `prod` env and overrides for it and want to create `prod-europe` and `prod-usa` envs that include all properties from `prod` and can have their own overrides.
The easiest way to do this is to define `prod` profile in `prod-europe` and `prod-usa` env descriptors:

**envs/prod.yaml**
```yaml
core:
  componets:
   - order-service
   - payment-service
  ...
```
**envs/prod-europe.yaml**
```yaml
include
 env: prod # include all components from `prod` env

profiles: 
  - prod #include all configuration from prod envs
 ```

**envs/prod-usa.yaml**
```yaml
include
  env: prod # include all components from `prod` env

profiles: 
  - prod #include all configuration from prod envs
  - usa #include overrides from `usa` profiles (app.usa.yaml)
 ```

The config override priority for all components from `prod-usa` env:
* app.yaml `#without env`
* app.prod.yaml `#overrides for prod env`
* app.usa.yaml `#overrides for usa profile`
* app.prod-usa.yaml `#overrides for prod-usa env`

# Running the config build
As we discussed Microconfig has its own format for configuration sources. 
During the config build Microconfig inlines all includes, resolves placeholders, evaluates expression language, copies templates, and stores the result values into plain *.yaml or *.properties files to a dedicated folder for each service.

To run the build you can download Microconfig release from https://github.com/microconfig/microconfig/releases.

The required build params:
* `-r` - full or relative config root dir. 
* either `-e` or `-envs`.
    * `-e` - environment name (environment is used as a config profile, also as a group of services to build configs).
    * `-envs` - a comma separated list of environment names **without spaces**. Use `*` for all environments, and `!` to exclude an environment. E.g. `-envs *,!base`.  
`Tip: If you use zsh, be sure to escape the ! in your exclusions -> e.g. -envs *,\!base`

Optional build params:
* `-d` - full or relative build destination dir. Default = ${currentFolder}/build
* `-stacktrace` - Show full stacktrace in case of exceptions. Values: true/false. Default: false  

To build configs not for the whole environment but only for specific services you can use the following optional params:
* `-g` - a comma-separated list of component groups to build configs. 
* `-s` - a comma-separated list of services to build configs. 

Command line params example (Java 8+ required):
```
java -jar microconfig.jar -r repo -e prod
```

To add system properties use `-D`
```
java -DtaskId=3456 -DsomeParam=value -jar microconfig.jar -r repo -d configs -e prod
```

To speed up the build up to 3 times you can add `-XX:TieredStopAtLevel=1` Java VM param. 
For binary compiled distribution of MC(Mac, Linux, Win) you don't need XX:TieredStopAtLevel, it works ~5 times faster than jar version(cause we don't spend time in runtime to compile the code, but the peak performance is the same)
Although the build time for even big projects with hundreds of services is about 1-3 seconds.
```
java -XX:TieredStopAtLevel=1 -jar microconfig.jar -r repo -e prod
```

Let's see examples of initial and destination folder layouts: 

Initial source layout:
```
repo
└───common
|   └───logback-template 
|       └───logback.xml
└───core  
│   └───orders
│   │   └───application.yaml
│   │   └───process.proc
│   └───payments
│       └───application.yaml
│       └───process.proc
│	
└───infra
    └───service-discovery
    │   └───application.yaml
    │   └───process.proc
    └───api-gateway
        └───application.yaml
        └───process.proc
```
After build:
```
configs
└───orders
│   └───application.yaml
│   └───process.yaml
|   └───logback.xml
└───payments
│   └───application.yaml
│   └───process.yaml
|   └───logback.xml
└───service-discovery
│   └───application.yaml
│   └───process.yaml
|   └───logback.xml
└───api-gateway
    └───application.yaml
    └───process.yaml
    └───logback.xml
```

You can try to build configs from the dedicated example repo: https://github.com/microconfig/microconfig-quickstart 

## Viewing differences between config versions 
During the config build, Microconfig compares newly generated files to files generated during the previous build for each service for each config type.
Microconfig can detect added/removed/changed properties. 

Diff for application.yaml is stored in diff-application.yaml, diff for process.yaml is stored in diff-process.yaml, etc.
```
configs
└───orders
│   └───application.yaml
│   └───diff-application.yaml
│   └───process.yaml
│   └───diff-process.yaml
│   └───logback.xml
```

The Diff format:

**diff-application.yaml**
```yaml     
+security.client.protocol: SSL # property has been added
-connection.timeoutMs: 1000 # property has been removed
 server.max-threads: 10 -> 35 # value has been changed from '10' to '35'
```

# YAML and Properties format support
Microconfig supports *.yaml and *.properties format for source and result configs.
You can keep a part of configuration in *.yaml files and another part in *.properties.

```
repo
└───core  
│   └───orders
│   │   └───application.yaml
│   │   └───process.proc
│   └───payments
│       └───application.properties
│       └───process.proc
```

Yaml configs can have nested properties:
```yaml
datasource:  
  minimum-pool-size: 2  
  maximum-pool-size: 5    
  timeout:
    ms: 10
```      

and lists:
```yaml
cluster.gateway:
  hosts:
    - 10.20.30.47
    - 15.20.30.47
    
```

Yaml format configs will be built into *.yaml, property configs will be built into *.properties. If *.properties configs include *.yaml configs, the resulting file will be *.yaml.
Microconfig can detect the format based on separators (if a config file has extension neither *.yaml nor *.properties). If you use `:` key-value separator, Microconfig will handle it like *.yaml (`=` for *.properties).

# Intellij IDEA plugin
To make configuration management a little bit easier you can use Microconfig Intellij IDEA plugin. The plugin can navigate to #include and placeholders' sources, show hints with resolved placeholders, and build configs from IDE.

See the documentation here: https://github.com/microconfig/microconfig-idea-plugin

# Contributing
If you want to contribute to the project and make it better, your help is very welcome. You can request a feature or submit a bug via issues. Or submit a pull request.

Contributing to the documentation is very welcome too.

Your Github 'Star' is appreciated!

https://github.com/microconfig/microconfig

# Contacts
[Join our Slack!](https://join.slack.com/t/microconfig/shared_invite/zt-dflf2m0n-wOPVfAmk5eiHPn_9Omff7Q)

support@microconfig.io


================================================
FILE: agent.sh
================================================
.graalvm/bin/java -agentlib:native-image-agent=config-merge-dir=microconfig-cli/src/main/resources/META-INF/native-image \
  -jar microconfig-cli/build/libs/microconfig-cli-*-all.jar \
  -r ~/microconfig/microconfig-quickstart -d ~/microconfig/microconfig-quickstart/build -e dev $1

================================================
FILE: build.gradle
================================================
apply from: 'lib.gradle'
apply from: 'pomSettings.gradle'

buildscript {
    repositories {
        mavenCentral()
        maven {
            url = uri("https://plugins.gradle.org/m2/")
        }
    }

    dependencies {
        classpath "com.github.johnrengelman:shadow:8.1.1"
        classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:5.1.0.4882'
    }
}

allprojects {
    apply plugin: 'java'
    apply plugin: 'jacoco'
    apply plugin: 'maven-publish'
    apply plugin: 'org.sonarqube'

    apply plugin: 'signing'

    group = 'io.microconfig'
    version = rootProject.version

    sourceCompatibility = 17
    targetCompatibility = 17

    repositories {
        mavenCentral()
    }

    java {
        withJavadocJar()
        withSourcesJar()
    }

    publishing {
        publications {
            nexus(MavenPublication) {
                pom.withXml {
                    def root = asNode()
                    root.appendNode('description', pomDescription)
                    root.children().last() + pomConfig
                }
                from components.java
            }
        }
        repositories {
            maven {
                url = "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
                credentials {
                    username ossrhUsername
                    password ossrhPassword
                }
            }
        }
    }

    signing {
        sign publishing.publications.nexus
    }

    dependencies {
        implementation platform(lib.spring_bom)

        compileOnly lib.lombok
        testCompileOnly lib.lombok
        annotationProcessor lib.lombok

        testImplementation lib.junit, lib.mokito
    }

    sonarqube {
        properties {
            property "sonar.projectKey", "microconfig_microconfig"
        }
    }

    jacocoTestReport {
        reports {
            xml.required = true
            html.required = true
        }
    }


    test {
        useJUnitPlatform()
        exclude '**/*IT.class'
    }

    task sourceJar(type: Jar) {
        from sourceSets.main.allJava
    }
}

================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists


================================================
FILE: gradle.properties
================================================
version=4.9.5

org.gradle.daemon=true
org.gradle.jvmargs=-Dfile.encoding\=UTF-8
org.gradle.parallel=true

ossrhUsername=
ossrhPassword=

signing.keyId=
signing.password=
signing.secretKeyRingFile=

================================================
FILE: gradlew
================================================
#!/usr/bin/env sh

##############################################################################
##
##  Gradle start up script for UN*X
##
##############################################################################

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`"/$link"
    fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn () {
    echo "$*"
}

die () {
    echo
    echo "$*"
    echo
    exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
  CYGWIN* )
    cygwin=true
    ;;
  Darwin* )
    darwin=true
    ;;
  MINGW* )
    msys=true
    ;;
  NONSTOP* )
    nonstop=true
    ;;
esac

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD="$JAVA_HOME/jre/sh/java"
    else
        JAVACMD="$JAVA_HOME/bin/java"
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD="java"
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
    MAX_FD_LIMIT=`ulimit -H -n`
    if [ $? -eq 0 ] ; then
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
            MAX_FD="$MAX_FD_LIMIT"
        fi
        ulimit -n $MAX_FD
        if [ $? -ne 0 ] ; then
            warn "Could not set maximum file descriptor limit: $MAX_FD"
        fi
    else
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
    fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
    JAVACMD=`cygpath --unix "$JAVACMD"`

    # We build the pattern for arguments to be converted via cygpath
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
    SEP=""
    for dir in $ROOTDIRSRAW ; do
        ROOTDIRS="$ROOTDIRS$SEP$dir"
        SEP="|"
    done
    OURCYGPATTERN="(^($ROOTDIRS))"
    # Add a user-defined pattern to the cygpath arguments
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
    fi
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    i=0
    for arg in "$@" ; do
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option

        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
        else
            eval `echo args$i`="\"$arg\""
        fi
        i=$((i+1))
    done
    case $i in
        (0) set -- ;;
        (1) set -- "$args0" ;;
        (2) set -- "$args0" "$args1" ;;
        (3) set -- "$args0" "$args1" "$args2" ;;
        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
    esac
fi

# Escape application args
save () {
    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
    echo " "
}
APP_ARGS=$(save "$@")

# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"

# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
  cd "$(dirname "$0")"
fi

exec "$JAVACMD" "$@"


================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto init

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:init
@rem Get command-line arguments, handling Windows variants

if not "%OS%" == "Windows_NT" goto win9xME_args

:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2

:win9xME_args_slurp
if "x%~1" == "x" goto execute

set CMD_LINE_ARGS=%*

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: lib.gradle
================================================
ext {
    lib = [
            spring_bom: "org.springframework.boot:spring-boot-dependencies:3.3.3",
            lombok    : 'org.projectlombok:lombok:1.18.34',
            mustache  : 'com.samskivert:jmustache:1.16',
            spring_el : 'org.springframework:spring-expression',
            snakeyaml : 'org.yaml:snakeyaml',
            gson      : 'com.google.code.gson:gson',
            junit     : ['org.junit.jupiter:junit-jupiter-engine', 'org.junit.jupiter:junit-jupiter-params'],
            mokito    : 'org.mockito:mockito-junit-jupiter',
    ].withDefault({ key -> throw new IllegalArgumentException("Unknown library '$key'") })
}

================================================
FILE: lombok.config
================================================
lombok.anyConstructor.addConstructorProperties=true
lombok.addLombokGeneratedAnnotation=true

================================================
FILE: microconfig-api/build.gradle
================================================
dependencies {
    implementation project(':utils')
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/configtypes/ConfigType.java
================================================
package io.microconfig.core.configtypes;

import java.util.Set;

public interface ConfigType {
    String getName();

    Set<String> getSourceExtensions();

    String getResultFileName();
}


================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/configtypes/ConfigTypeFilter.java
================================================
package io.microconfig.core.configtypes;

import java.util.List;

public interface ConfigTypeFilter {
    List<ConfigType> selectTypes(List<ConfigType> supportedTypes);
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/configtypes/ConfigTypeFilters.java
================================================
package io.microconfig.core.configtypes;

import lombok.RequiredArgsConstructor;

import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import static io.microconfig.utils.CollectionUtils.setOf;
import static io.microconfig.utils.FileUtils.getExtension;
import static io.microconfig.utils.StreamUtils.filter;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toSet;
import static lombok.AccessLevel.PRIVATE;

@RequiredArgsConstructor(access = PRIVATE)
public class ConfigTypeFilters {
    public static ConfigTypeFilter eachConfigType() {
        return types -> types;
    }

    public static ConfigTypeFilter configType(ConfigType... types) {
        return __ -> {
            if (types.length == 0) {
                throw noConfigTypesProvidedException();
            }
            return asList(types);
        };
    }

    public static ConfigTypeFilter configTypeWithName(String... name) {
        Set<String> names = setOf(name);
        if (names.isEmpty()) {
            throw noConfigTypesProvidedException();
        }
        return types -> {
            validateNames(names, types);
            return filter(types, type -> names.contains(type.getName()));
        };
    }

    public static ConfigTypeFilter configTypeWithExtensionOf(File file) {
        String ext = getExtension(file);
        if (ext.isEmpty()) {
            throw new IllegalArgumentException("File " + file + " doesn't have an extension. Unable to resolve component type.");
        }
        return types -> types.stream()
                .filter(t -> t.getSourceExtensions().contains(ext))
                .findFirst()
                .map(Collections::singletonList)
                .orElseThrow(() -> new IllegalArgumentException("Unsupported config extension '" + ext + "'"));
    }

    private static void validateNames(Set<String> names, List<ConfigType> supportedTypes) {
        Set<String> supportedNames = supportedTypes.stream().map(ConfigType::getName).collect(toSet());
        List<String> unsupportedNames = filter(names, n -> !supportedNames.contains(n));
        if (!unsupportedNames.isEmpty()) {
            throw new IllegalArgumentException("Unsupported config types: " + unsupportedNames + " Configured types: " + supportedNames);
        }
    }

    private static IllegalArgumentException noConfigTypesProvidedException() {
        return new IllegalArgumentException("No config types provided");
    }
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/configtypes/ConfigTypeRepository.java
================================================
package io.microconfig.core.configtypes;

import java.util.List;

public interface ConfigTypeRepository {
    List<ConfigType> getConfigTypes();
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/environments/Component.java
================================================
package io.microconfig.core.environments;

import io.microconfig.core.configtypes.ConfigTypeFilter;
import io.microconfig.core.properties.Properties;

public interface Component {
    String getName();

    String getOriginalName();

    String getEnvironment();

    Properties getPropertiesFor(ConfigTypeFilter filter);
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/environments/ComponentGroup.java
================================================
package io.microconfig.core.environments;

import java.util.Optional;

public interface ComponentGroup {
    String getName();

    Optional<String> getIp();

    Components getComponents();

    Optional<Component> findComponentWithName(String name);
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/environments/Components.java
================================================
package io.microconfig.core.environments;

import io.microconfig.core.configtypes.ConfigTypeFilter;
import io.microconfig.core.properties.Properties;

import java.util.List;

public interface Components {
    List<Component> asList();

    Properties getPropertiesFor(ConfigTypeFilter filter);
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/environments/Environment.java
================================================
package io.microconfig.core.environments;

import java.io.File;
import java.util.List;
import java.util.Optional;

public interface Environment {
    String getName();

    File getSource();

    boolean isAbstract();

    int getPortOffset();

    List<String> getProfiles();

    List<ComponentGroup> getGroups();

    List<ComponentGroup> findGroupsWithIp(String ip);

    ComponentGroup getGroupWithName(String groupName);

    Optional<ComponentGroup> findGroupWithComponent(String componentName);

    Components getAllComponents();

    Component getComponentWithName(String componentName);

    Components findComponentsFrom(List<String> groups, List<String> components);

    Component findComponentWithName(String componentName);
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/environments/EnvironmentRepository.java
================================================
package io.microconfig.core.environments;

import java.util.List;
import java.util.Set;

public interface EnvironmentRepository {
    List<Environment> environments();

    Set<String> environmentNames();

    Environment getByName(String name);

    Environment getOrCreateByName(String name);
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/exceptions/MicroconfigException.java
================================================
package io.microconfig.core.exceptions;

import lombok.NoArgsConstructor;

@NoArgsConstructor
public class MicroconfigException extends RuntimeException {
    public MicroconfigException(String message) {
        super(message);
    }

    public MicroconfigException(String message, Throwable cause) {
        super(message, cause);
    }
}


================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/properties/ConfigFormat.java
================================================
package io.microconfig.core.properties;

public enum ConfigFormat {
    YAML,
    PROPERTIES;

    public String extension() {
        return '.' + name().toLowerCase();
    }
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/properties/DeclaringComponent.java
================================================
package io.microconfig.core.properties;

public interface DeclaringComponent {
    String getConfigType();

    String getComponent();

    String getEnvironment();
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/properties/PlaceholderResolveStrategy.java
================================================
package io.microconfig.core.properties;

import java.util.Optional;

public interface PlaceholderResolveStrategy {
    Optional<Property> resolve(String component, String key, String environment, String configType, String root);
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/properties/Properties.java
================================================
package io.microconfig.core.properties;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;

public interface Properties {
    Properties resolveBy(Resolver resolver);

    Properties withoutVars();

    Properties without(Predicate<Property> excluded);

    Properties withPrefix(String prefix);

    Map<String, Property> getPropertiesAsMap();

    Map<String, String> getPropertiesAsKeyValue();

    Collection<Property> getProperties();

    Optional<Property> getPropertyWithKey(String key);

    <T> List<T> save(PropertySerializer<T> serializer);

    List<TypedProperties> asTypedProperties();

    Properties forEachComponent(UnaryOperator<TypedProperties> callback);

    TypedProperties first();
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/properties/PropertiesFactory.java
================================================
package io.microconfig.core.properties;

import io.microconfig.core.configtypes.ConfigType;

import java.util.List;

public interface PropertiesFactory {
    Properties getPropertiesOf(String componentName,
                               String componentOriginalName,
                               String environment,
                               List<ConfigType> configTypes);

    Properties flat(List<Properties> properties);
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/properties/Property.java
================================================
package io.microconfig.core.properties;

public interface Property {
    String getKey();

    String getValue();

    boolean isVar();

    ConfigFormat getConfigFormat();

    DeclaringComponent getDeclaringComponent();

    Property resolveBy(Resolver resolver, DeclaringComponent root);
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/properties/PropertySerializer.java
================================================
package io.microconfig.core.properties;

import io.microconfig.core.configtypes.ConfigType;
import io.microconfig.core.templates.Template;

import java.util.Collection;
import java.util.List;

public interface PropertySerializer<T> {
    T serialize(Collection<Property> properties,
                List<Template> templates,
                ConfigType configType,
                String componentName,
                String environment);
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/properties/Resolver.java
================================================
package io.microconfig.core.properties;

public interface Resolver {
    String resolve(String value, DeclaringComponent sourceOfValue, DeclaringComponent root);
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/properties/TypedProperties.java
================================================
package io.microconfig.core.properties;

import io.microconfig.core.configtypes.ConfigType;
import io.microconfig.core.templates.Template;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;

public interface TypedProperties {
    ConfigType getConfigType();

    DeclaringComponent getDeclaringComponent();

    TypedProperties resolveBy(Resolver resolver);

    TypedProperties withoutVars();

    TypedProperties without(Predicate<Property> excluded);

    TypedProperties withPrefix(String prefix);

    TypedProperties withTemplates(List<Template> templates);

    Map<String, Property> getPropertiesAsMap();

    Map<String, String> getPropertiesAsKeyValue();

    Collection<Property> getProperties();

    Optional<Property> getPropertyWithKey(String key);

    <T> T save(PropertySerializer<T> serializer);
}

================================================
FILE: microconfig-api/src/main/java/io/microconfig/core/templates/Template.java
================================================
package io.microconfig.core.templates;

import java.io.File;

public interface Template {
    File getSource();

    File getDestination();

    String getFileName();

    String getContent();

    byte[] getContentAsBytes();
}

================================================
FILE: microconfig-api/src/test/java/io/microconfig/core/configtypes/ConfigTypeFiltersTest.java
================================================
package io.microconfig.core.configtypes;

import org.junit.jupiter.api.Test;

import java.io.File;
import java.util.List;

import static io.microconfig.core.configtypes.ConfigTypeFilters.*;
import static io.microconfig.utils.CollectionUtils.setOf;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class ConfigTypeFiltersTest {
    ConfigType app = type("app");
    ConfigType process = type("process");
    ConfigType deploy = type("deploy");
    List<ConfigType> supportedTypes = asList(app, process, deploy);

    @Test
    void selectEachConfigType() {
        assertEquals(
                supportedTypes,
                eachConfigType().selectTypes(supportedTypes)
        );
    }

    @Test
    void useProvidedTypes() {
        ConfigType testType = type("provided");
        assertEquals(
                singletonList(testType),
                configType(testType).selectTypes(supportedTypes)
        );
    }

    @Test
    void selectByConfigName() {
        assertEquals(
                asList(app, deploy),
                configTypeWithName("app", "deploy").selectTypes(supportedTypes)
        );
    }

    @Test
    void failOnUnsupportedName() {
        assertThrows(IllegalArgumentException.class, () -> configTypeWithName("app", "badName").selectTypes(supportedTypes));
    }

    @Test
    void failOnEmptyNames() {
        assertThrows(IllegalArgumentException.class, () -> configTypeWithName().selectTypes(supportedTypes));
        assertThrows(IllegalArgumentException.class, () -> configType().selectTypes(supportedTypes));
    }

    @Test
    void selectByFileExtension() {
        assertEquals(
                singletonList(app),
                configTypeWithExtensionOf(new File("application.app")).selectTypes(supportedTypes)
        );
    }

    @Test
    void failOnFileWithoutExtension() {
        File badFile = new File("application");
        assertThrows(IllegalArgumentException.class, () -> configTypeWithExtensionOf(badFile).selectTypes(supportedTypes));
    }

    private ConfigType type(String name) {
        ConfigType ct = mock(ConfigType.class);
        when(ct.getName()).thenReturn(name);
        when(ct.getResultFileName()).thenReturn("file-" + name);
        when(ct.getSourceExtensions()).thenReturn(setOf("." + name));
        return ct;
    }
}

================================================
FILE: microconfig-api/src/test/java/io/microconfig/core/properties/ConfigFormatTest.java
================================================
package io.microconfig.core.properties;

import org.junit.jupiter.api.Test;

import static io.microconfig.core.properties.ConfigFormat.PROPERTIES;
import static io.microconfig.core.properties.ConfigFormat.YAML;
import static org.junit.jupiter.api.Assertions.assertEquals;

class ConfigFormatTest {
    @Test
    void extension() {
        assertEquals(".yaml", YAML.extension());
        assertEquals(".properties", PROPERTIES.extension());
    }
}

================================================
FILE: microconfig-cli/build.gradle
================================================
apply plugin: 'application'
apply plugin: 'maven-publish'
apply plugin: 'com.github.johnrengelman.shadow'

mainClassName = 'io.microconfig.MicroconfigMain'

publishing {
    publications {
        shadow(MavenPublication) { publication ->
            project.shadow.component(publication)
            afterEvaluate {
                pom.withXml {
                    def root = asNode()
                    root.appendNode('description', pomDescription)
                    root.children().last() + pomConfig
                }
            }
        }
    }
}

task copyVersion {
    doLast {
        ant.copy file: "${rootDir}/gradle.properties",
                tofile: "${buildDir}/resources/main/version.properties"
    }
}

compileJava.finalizedBy(copyVersion)


signing {
    sign publishing.publications.shadow
}

dependencies {

    implementation project(':microconfig-core'),
            project(':utils')
}

================================================
FILE: microconfig-cli/src/main/java/io/microconfig/CommandLineParamParser.java
================================================
package io.microconfig;

import lombok.RequiredArgsConstructor;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static io.microconfig.utils.Logger.error;
import static io.microconfig.utils.StringUtils.isEmpty;
import static io.microconfig.utils.StringUtils.split;

@RequiredArgsConstructor
public class CommandLineParamParser {
    private final Map<String, String> keyToValue;

    public static CommandLineParamParser parse(String... args) {
        Map<String, String> params = new HashMap<>();
        for (int i = 0; i < args.length; i += 2) {
            String key = args[i];
            String value = i < args.length - 1 ? args[i + 1] : null;
            if (!key.startsWith("-")) {
                printErrorAndExit("key '" + key + "' must start with -");
            }
            params.put(key.substring(1), value);
        }

        return new CommandLineParamParser(params);
    }

    public String value(String key) {
        return valueOr(key, null);
    }

    public String valueOr(String key, String defaultValue) {
        String value = keyToValue.get(key);
        if (isEmpty(value)) return defaultValue;

        return value.startsWith("\"") && value.endsWith("\"") ?
                value.substring(1, value.length() - 1) : value;
    }

    public List<String> listValue(String key) {
        return split(value(key), ",");
    }

    public String requiredValue(String key, String npeMessage) {
        String value = value(key);
        if (value != null) return value;

        printErrorAndExit(npeMessage);
        throw new AssertionError("Impossible");
    }

    public static void printErrorAndExit(String npeMessage) {
        error(npeMessage);
        System.exit(-1);
    }

    public boolean booleanValue(String key) {
        return "true".equals(value(key));
    }

    public boolean contains(String key) {
        return keyToValue.containsKey(key);
    }
}

================================================
FILE: microconfig-cli/src/main/java/io/microconfig/MicroconfigMain.java
================================================
package io.microconfig;

import io.microconfig.core.MicroconfigRunner;
import io.microconfig.core.properties.Properties;
import io.microconfig.core.properties.serializers.ConfigResult;
import lombok.RequiredArgsConstructor;
import lombok.val;

import java.io.File;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import static io.microconfig.core.properties.serializers.ConfigResult.toJson;
import static io.microconfig.core.properties.serializers.PropertySerializers.asConfigResult;
import static io.microconfig.utils.IoUtils.readClasspathResource;
import static io.microconfig.utils.Logger.*;
import static java.lang.System.exit;
import static java.lang.System.nanoTime;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import static java.util.stream.Collectors.toCollection;

/**
 * Command line params example: *
 * -r configs/repo -d build -e dev
 * <p>
 * VM speedup params:
 * -XX:TieredStopAtLevel=1
 */
@RequiredArgsConstructor
public class MicroconfigMain {
    private final File rootDir;
    private final String destinationDir;
    private final Set<String> environments;
    private final List<String> groups;
    private final List<String> services;
    private final boolean stacktrace;
    private final boolean jsonOutput;
    private final boolean isSingleEnvBuild;

    public static void main(String... args) {
        val params = MicroconfigParams.parse(args);
        if (params.version()) {
            printVersion();
            return;
        }

        File rootDir = params.rootDir();
        String destinationDir = params.destinationDir();
        Set<String> environments = params.environments();
        List<String> groups = params.groups();
        List<String> services = params.services();
        boolean stacktrace = params.stacktrace();
        boolean jsonOutput = params.jsonOutput();
        boolean isSingleEnvBuild = params.isSingleEnvBuild();

        new MicroconfigMain(rootDir, destinationDir, environments, groups, services,
                stacktrace, jsonOutput, isSingleEnvBuild)
                .build();
    }

    private void build() {
        try {
            enableLogger(!jsonOutput);
            doBuild();
        } catch (RuntimeException e) {
            if (stacktrace || e.getMessage() == null) throw e;
            error(e.getMessage());
            exit(-1);
        }
    }

    private void doBuild() {
        environmentsToBuild().forEach(env -> {
            long startTime = nanoTime();
            String resultDestinationDir = isSingleEnvBuild ? destinationDir : destinationDir + "/" + env;
            MicroconfigRunner runner = new MicroconfigRunner(rootDir, new File(resultDestinationDir));
            Properties properties = runner.buildProperties(env, groups, services);
            if (jsonOutput) {
                List<ConfigResult> results = properties.save(asConfigResult());
                System.out.println(toJson(results));
            } else {
                properties.save(runner.toFiles());
            }
            announce("\nGenerated [" + env + "] configs in " + (NANOSECONDS.toMillis(nanoTime() - startTime)) + "ms");
        });
    }

    private Set<String> environmentsToBuild() {
        if (!environments.contains("*")) {
            return environments.stream()
                    .filter(e -> !e.startsWith("!"))
                    .collect(toCollection(LinkedHashSet::new));
        }

        return new MicroconfigRunner(rootDir, new File(destinationDir))
                .getMicroconfig()
                .environments()
                .environmentNames()
                .stream()
                .filter(e -> !environments.contains("!" + e))
                .collect(toCollection(LinkedHashSet::new));
    }

    private static void printVersion() {
        String version = readClasspathResource("version.properties")
                .split("\n")[0]
                .split("=")[1]
                .trim();
        info(version);
    }
}

================================================
FILE: microconfig-cli/src/main/java/io/microconfig/MicroconfigParams.java
================================================
package io.microconfig;

import lombok.RequiredArgsConstructor;

import java.io.File;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import static io.microconfig.CommandLineParamParser.printErrorAndExit;

@RequiredArgsConstructor
public class MicroconfigParams {
    private final CommandLineParamParser parser;

    public static MicroconfigParams parse(String... args) {
        return new MicroconfigParams(CommandLineParamParser.parse(args));
    }

    public File rootDir() {
        return new File(parser.valueOr("r", "."));
    }

    public String destinationDir() {
        return parser.valueOr("d", "build");
    }

    public List<String> groups() {
        return parser.listValue("g");
    }

    public List<String> services() {
        return parser.listValue("s");
    }

    public boolean stacktrace() {
        return parser.booleanValue("stacktrace");
    }

    public boolean version() {
        return parser.contains("v");
    }

    public boolean jsonOutput() {
        return "json".equals(parser.value("output"));
    }

    public Set<String> environments() {
        Set<String> environments = new LinkedHashSet<>(parser.listValue("envs"));
        String env = parser.value("e");
        if (env != null) {
            if (env.equals("*")) {
                printErrorAndExit("use -envs instead of -e to pass `*` as a value");
            }
            environments.add(env);
        }
        if (environments.isEmpty()) {
            printErrorAndExit("set `-e (environment)` or `-envs (env1),(env2)...`");
        }
        return environments;
    }

    public boolean isSingleEnvBuild() {
        return parser.contains("e") && !parser.contains("envs");
    }
}

================================================
FILE: microconfig-cli/src/main/resources/META-INF/native-image/jni-config.json
================================================
[
{
  "name":"java.lang.ClassLoader",
  "methods":[
    {"name":"getPlatformClassLoader","parameterTypes":[] }, 
    {"name":"loadClass","parameterTypes":["java.lang.String"] }
  ]
},
{
  "name":"java.lang.ClassNotFoundException"
},
{
  "name":"java.lang.NoSuchMethodError"
}
]


================================================
FILE: microconfig-cli/src/main/resources/META-INF/native-image/native-image.properties
================================================
Args = --no-fallback \
    --report-unsupported-elements-at-runtime \
    --initialize-at-build-time=io.microconfig.core.properties.PropertiesRepository \
    --initialize-at-build-time=io.microconfig.core.properties.PropertiesFactory \
    --initialize-at-build-time=io.microconfig.core.properties.PlaceholderResolveStrategy \
    --initialize-at-build-time=io.microconfig.core.properties.DeclaringComponent \
    --initialize-at-build-time=io.microconfig.core.properties.resolvers.RecursiveResolver \
    --initialize-at-build-time=io.microconfig.core.properties.resolvers.expression.ExpressionResolver \
    --initialize-at-build-time=io.microconfig.core.properties.io.selector.ConfigFormatDetector \
    --initialize-at-build-time=io.microconfig.core.environments.EnvironmentRepository \
    --initialize-at-build-time=io.microconfig.core.environments.ComponentFactory \
    --initialize-at-build-time=io.microconfig.core.configtypes.ConfigTypeRepository \
    --initialize-at-build-time=io.microconfig.core.configtypes.ConfigType

ImageName=microconfig

================================================
FILE: microconfig-cli/src/main/resources/META-INF/native-image/proxy-config.json
================================================
[
  ["io.microconfig.core.configtypes.ConfigTypeRepository"],
  ["io.microconfig.core.environments.ComponentFactory"],
  ["io.microconfig.core.environments.EnvironmentRepository"],
  ["io.microconfig.core.properties.PlaceholderResolveStrategy"],
  ["io.microconfig.core.properties.PropertiesFactory"],
  ["io.microconfig.core.properties.PropertiesRepository"],
  ["io.microconfig.core.properties.io.selector.ConfigFormatDetector"],
  ["io.microconfig.core.properties.resolvers.RecursiveResolver"]
]


================================================
FILE: microconfig-cli/src/main/resources/META-INF/native-image/reflect-config.json
================================================
[
{
  "name":"com.oracle.truffle.api.TruffleLanguage"
},
{
  "name":"com.oracle.truffle.api.debug.impl.DebuggerInstrumentProvider",
  "methods":[{"name":"<init>","parameterTypes":[] }]
},
{
  "name":"com.oracle.truffle.api.instrumentation.TruffleInstrument"
},
{
  "name":"com.oracle.truffle.api.interop.DefaultBooleanExportsGen"
},
{
  "name":"com.oracle.truffle.api.interop.DefaultByteExportsGen"
},
{
  "name":"com.oracle.truffle.api.interop.DefaultCharacterExportsGen"
},
{
  "name":"com.oracle.truffle.api.interop.DefaultDoubleExportsGen"
},
{
  "name":"com.oracle.truffle.api.interop.DefaultFloatExportsGen"
},
{
  "name":"com.oracle.truffle.api.interop.DefaultIntegerExportsGen"
},
{
  "name":"com.oracle.truffle.api.interop.DefaultLongExportsGen"
},
{
  "name":"com.oracle.truffle.api.interop.DefaultShortExportsGen"
},
{
  "name":"com.oracle.truffle.api.interop.DefaultStringExportsGen"
},
{
  "name":"com.oracle.truffle.api.interop.InteropLibraryGen"
},
{
  "name":"io.microconfig.core.properties.resolvers.expression.functions.CustomStringApi",
  "allPublicMethods":true
},
{
  "name":"io.microconfig.core.properties.resolvers.expression.functions.CustomIoApi",
  "allPublicMethods":true
},
{
  "name":"io.microconfig.core.properties.serializers.ConfigResult$FileResult",
  "allDeclaredFields":true
},
{
  "name":"io.microconfig.core.properties.serializers.ConfigResult$ServiceConfigs",
  "allDeclaredFields":true
},
{
  "name":"java.io.ObjectInputStream",
  "allPublicMethods":true
},
{
  "name":"java.io.Serializable",
  "allPublicMethods":true
},
{
  "name":"java.lang.CharSequence",
  "allPublicMethods":true
},
{
  "name":"java.lang.Comparable",
  "allPublicMethods":true
},
{
  "name":"java.lang.Object",
  "allDeclaredMethods":true
},
{
  "name":"java.lang.String",
  "allDeclaredMethods":true,
  "allPublicMethods":true
},
{
  "name":"java.lang.System",
  "allPublicMethods":true
},
{
  "name":"java.lang.reflect.AccessibleObject",
  "fields":[{"name":"override"}]
},
{
  "name":"java.sql.Date"
},
{
  "name":"java.sql.Timestamp"
},
{
  "name":"java.util.ArrayList",
  "methods":[{"name":"<init>","parameterTypes":[] }]
},
{
  "name":"org.springframework.util.ConcurrentReferenceHashMap$Segment[]"
},
{
  "name":"sun.misc.Unsafe",
  "fields":[{"name":"theUnsafe"}],
  "methods":[
    {"name":"allocateInstance","parameterTypes":["java.lang.Class"] }, 
    {"name":"objectFieldOffset","parameterTypes":["java.lang.reflect.Field"] }, 
    {"name":"putBoolean","parameterTypes":["java.lang.Object","long","boolean"] }
  ]
}
]


================================================
FILE: microconfig-cli/src/main/resources/META-INF/native-image/resource-config.json
================================================
{
  "resources":[
    {"pattern":"\\QMETA-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat\\E"}, 
    {"pattern":"\\QMETA-INF/services/com.oracle.truffle.api.TruffleLanguage$Provider\\E"}, 
    {"pattern":"\\QMETA-INF/services/com.oracle.truffle.api.instrumentation.TruffleInstrument$Provider\\E"}, 
    {"pattern":"\\QMETA-INF/services/org.apache.logging.log4j.spi.Provider\\E"}, 
    {"pattern":"\\QMETA-INF/services/org.apache.logging.log4j.util.PropertySource\\E"}, 
    {"pattern":"\\Qcom/oracle/truffle/nfi/impl/NFILanguageImpl.class\\E"}, 
    {"pattern":"\\Qlog4j2.xml\\E"}, 
    {"pattern":"\\Qversion.properties\\E"}
  ],
  "bundles":[]
}


================================================
FILE: microconfig-cli/src/main/resources/log4j2.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="fatal">
    <Loggers>
        <Root level="OFF">
        </Root>
    </Loggers>
</Configuration>

================================================
FILE: microconfig-cli/src/test/java/io/microconfig/CommandLineParamParserTest.java
================================================
package io.microconfig;

import org.junit.jupiter.api.Test;

import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.junit.jupiter.api.Assertions.assertEquals;

class CommandLineParamParserTest {
    @Test
    void parse() {
        CommandLineParamParser params = CommandLineParamParser.parse("-r", "/home/repo", "-d", "/home/repo/dest", "-e", "dev6", "-envs", "dev7, dev8", "-s", "s1,s2", "-q");
        assertEquals("/home/repo", params.value("r"));
        assertEquals("/home/repo/dest", params.value("d"));
        assertEquals("dev6", params.value("e"));
        assertEquals(asList("dev7", "dev8"), params.listValue("envs"));
        assertEquals(asList("s1", "s2"), params.listValue("s"));
        assertEquals(emptyList(), params.listValue("empty"));
    }
}

================================================
FILE: microconfig-cli/src/test/java/io/microconfig/MicroconfigMainTest.java
================================================
package io.microconfig;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import java.io.File;
import java.util.List;

import static io.microconfig.utils.FileUtils.getName;
import static io.microconfig.utils.IoUtils.readFully;
import static java.util.Arrays.asList;
import static org.junit.jupiter.api.Assertions.assertEquals;

class MicroconfigMainTest {
    @TempDir
    File destinationDir;

    final static List<String> components = asList("component", "component2");

    private String root;

    @BeforeEach
    void setup() {
        root = getClass().getClassLoader().getResource("repo").getFile();
    }

    @Test
    void should_generate_config_for_single_env_when_e_param_given() {
        MicroconfigMain.main("-e", "env1", "-r", escape(root), "-d", escape(destinationDir.getAbsolutePath()));
        checkConfigGeneratedFor("component", null);
        checkConfigGeneratedFor("component2", null);
    }

    @Test
    void should_generate_config_for_multiple_envs_when_envs_param_given() {
        List<String> environments = asList("env2", "env3");
        MicroconfigMain.main("-envs", String.join(",", environments), "-r", escape(root), "-d", escape(destinationDir.getAbsolutePath()));
        for (String component : components) {
            for (String environment : environments) {
                checkConfigGeneratedFor(component, environment);
            }
        }
    }

    @ParameterizedTest
    @ValueSource(strings = {"env1, *", "*, env1", "*"})
    void should_generate_config_for_all_envs_when_star_in_envs_list(String envs) {
        MicroconfigMain.main("-envs", envs, "-r", escape(root), "-d", escape(destinationDir.getAbsolutePath()));
        for (String component : components) {
            for (String environment : asList("env1", "env2")) {
                checkConfigGeneratedFor(component, environment);
            }
        }
    }

    @Test
    void should_not_generate_config_for_excluded_envs() {
        String envs = "env1, !env2, env3";
        MicroconfigMain.main("-envs", envs, "-r", escape(root), "-d", escape(destinationDir.getAbsolutePath()));
        for (String component : components) {
            for (String environment : asList("env1", "env3")) {
                checkConfigGeneratedFor(component, environment);
            }
            checkConfigNotGeneratedFor(component, "env2");
        }
    }

    private String escape(String name) {
        return "\"" + name + "\"";
    }

    private void checkConfigGeneratedFor(String component, String nestedDirectory) {
        checkComponentBuildResult(component, nestedDirectory, true);
    }

    private void checkConfigNotGeneratedFor(String component, String nestedDirectory) {
        checkComponentBuildResult(component, nestedDirectory, false);
    }

    private void checkComponentBuildResult(String component, String nestedDirectory, boolean shouldFileExist) {
        checkFileExist(buildFilePath(component, "application.yaml", nestedDirectory), shouldFileExist);
        checkFileExist(buildFilePath(component, "deploy.yaml", nestedDirectory), shouldFileExist);
    }

    private String buildFilePath(String component, String fileName, String nestedDirectory) {
        String result = String.format("%s/%s/", component, fileName);
        if (nestedDirectory != null) {
            result = String.format("%s/%s", nestedDirectory, result);
        }
        return result;
    }

    private void checkFileExist(String filePath, boolean shouldFileExist) {
        File resultFile = new File(destinationDir, filePath);
        assertEquals(shouldFileExist, resultFile.exists());
        if (shouldFileExist) {
            assertEquals("key: " + getName(resultFile), readFully(resultFile).trim());
        }
    }
}

================================================
FILE: microconfig-cli/src/test/java/io/microconfig/MicroconfigParamsTest.java
================================================
package io.microconfig;

import org.junit.jupiter.api.Test;

import java.io.File;
import java.util.LinkedHashSet;

import static io.microconfig.MicroconfigParams.parse;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static org.junit.jupiter.api.Assertions.*;

class MicroconfigParamsTest {
    MicroconfigParams params = parse(
            "-r", "configs/repo",
            "-d", "destination",
            "-e", "dev",
            "-envs", "dev, test",
            "-g", "g1,g2",
            "-s", "s1, s2",
            "-output", "json"
    );
    MicroconfigParams empty = MicroconfigParams.parse();
    MicroconfigParams singleEnvBuild = parse("-e", "dev");

    @Test
    void rootDir() {
        assertEquals(new File("configs/repo"), params.rootDir());
    }

    @Test
    void destinationDir() {
        assertEquals("destination", params.destinationDir());
        assertEquals("build", empty.destinationDir());
    }

    @Test
    void env() {
        assertEquals("dev", params.environments().iterator().next());
    }

    @Test
    void envs() {
        assertEquals(new LinkedHashSet<>(asList("dev", "test")), params.environments());
    }

    @Test
    void groups() {
        assertEquals(asList("g1", "g2"), params.groups());
        assertEquals(emptyList(), empty.groups());
    }

    @Test
    void services() {
        assertEquals(asList("s1", "s2"), params.services());
        assertEquals(emptyList(), empty.services());
    }

    @Test
    void jsonOutput() {
        assertFalse(empty.jsonOutput());
        assertTrue(params.jsonOutput());
    }

    @Test
    void testVersion() {
        assertTrue(parse("-v").version());
    }

    @Test
    void isSingleEnvBuild() {
        assertFalse(params.isSingleEnvBuild());
        assertTrue(singleEnvBuild.isSingleEnvBuild());
    }
}

================================================
FILE: microconfig-cli/src/test/resources/repo/components/component/application.yaml
================================================
key: application

================================================
FILE: microconfig-cli/src/test/resources/repo/components/component/os.deploy
================================================
key: deploy

================================================
FILE: microconfig-cli/src/test/resources/repo/envs/env1.yaml
================================================
group:
  components:
    - component
    - component2:component

================================================
FILE: microconfig-cli/src/test/resources/repo/envs/env2.yaml
================================================
group:
  components:
    - component
    - component2:component

================================================
FILE: microconfig-cli/src/test/resources/repo/envs/env3.yaml
================================================
group:
  components:
    - component
    - component2:component

================================================
FILE: microconfig-core/build.gradle
================================================
apply plugin: 'java-library'

dependencies {
    api project(':microconfig-api')

    implementation project(':utils'),
            lib.mustache,
            lib.spring_el,
            lib.gson,
            lib.snakeyaml
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/Microconfig.java
================================================
package io.microconfig.core;

import io.microconfig.core.configtypes.ConfigTypeRepository;
import io.microconfig.core.configtypes.StandardConfigTypeRepository;
import io.microconfig.core.environments.ComponentFactory;
import io.microconfig.core.environments.ComponentFactoryImpl;
import io.microconfig.core.environments.Environment;
import io.microconfig.core.environments.EnvironmentRepository;
import io.microconfig.core.environments.repository.EnvironmentException;
import io.microconfig.core.environments.repository.FileEnvironmentRepository;
import io.microconfig.core.environments.repository.LazyInitEnvRepository;
import io.microconfig.core.properties.*;
import io.microconfig.core.properties.repository.ComponentGraph;
import io.microconfig.core.properties.repository.EnvProfilesComponentGraph;
import io.microconfig.core.properties.repository.FilePropertiesRepository;
import io.microconfig.core.properties.resolvers.RecursiveResolver;
import io.microconfig.core.properties.resolvers.expression.ExpressionResolver;
import io.microconfig.core.properties.resolvers.placeholder.PlaceholderResolver;
import io.microconfig.core.properties.resolvers.placeholder.strategies.component.ComponentProperty;
import io.microconfig.core.properties.resolvers.placeholder.strategies.component.ComponentResolveStrategy;
import io.microconfig.core.properties.resolvers.placeholder.strategies.component.properties.ComponentProperties;
import io.microconfig.core.properties.resolvers.placeholder.strategies.environment.EnvProperty;
import io.microconfig.core.properties.resolvers.placeholder.strategies.environment.EnvironmentResolveStrategy;
import io.microconfig.core.properties.resolvers.placeholder.strategies.environment.properties.EnvironmentProperties;
import io.microconfig.core.properties.resolvers.placeholder.strategies.standard.StandardResolveStrategy;
import io.microconfig.io.DumpedFsReader;
import io.microconfig.io.FsReader;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.With;
import lombok.experimental.Accessors;

import java.io.File;
import java.util.List;
import java.util.Map;

import static io.microconfig.core.configtypes.CompositeConfigTypeRepository.composite;
import static io.microconfig.core.configtypes.CustomConfigTypeRepository.findDescriptorIn;
import static io.microconfig.core.properties.io.selector.ConfigIoFactory.newConfigIo;
import static io.microconfig.core.properties.repository.ComponentGraphImpl.traverseFrom;
import static io.microconfig.core.properties.repository.CompositePropertiesRepository.compositeOf;
import static io.microconfig.core.properties.resolvers.ChainedResolver.chainOf;
import static io.microconfig.core.properties.resolvers.placeholder.strategies.composite.CompositeResolveStrategy.composite;
import static io.microconfig.core.properties.resolvers.placeholder.strategies.system.SystemResolveStrategy.envVariablesResolveStrategy;
import static io.microconfig.core.properties.resolvers.placeholder.strategies.system.SystemResolveStrategy.systemPropertiesResolveStrategy;
import static io.microconfig.utils.CacheProxy.cache;
import static io.microconfig.utils.CollectionUtils.join;
import static io.microconfig.utils.CollectionUtils.joinToSet;
import static io.microconfig.utils.FileUtils.canonical;
import static io.microconfig.utils.Logger.enableLogger;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;
import static lombok.AccessLevel.PRIVATE;

@Accessors(fluent = true)
@Getter
@RequiredArgsConstructor(access = PRIVATE)
public class Microconfig {
    private final File rootDir;
    @With
    private final File destinationDir;
    @With
    private final FsReader fsReader;
    @With
    private final List<PlaceholderResolveStrategy> additionalPlaceholderResolvers;
    @With
    private final List<PropertiesRepository> additionalPropertiesRepositories;

    private final Dependencies dependencies = new Dependencies();

    public static Microconfig searchConfigsIn(File rootDir) {
        File canonical = canonical(rootDir);
        if (!canonical.exists()) {
            throw new IllegalArgumentException("Root directory doesn't exist: " + rootDir);
        }
        return new Microconfig(canonical, new File(rootDir, "build"), new DumpedFsReader(), emptyList(), emptyList());
    }

    public Environment inEnvironment(String name) {
        Environment env = environments().getByName(name);
        if (env.isAbstract()) {
            throw new EnvironmentException("Can't build abstract environment " + name);
        }
        return env;
    }

    public EnvironmentRepository environments() {
        return dependencies.environments();
    }

    public Resolver resolver() {
        return dependencies.resolver();
    }

    public void logger(boolean enabled) {
        enableLogger(enabled);
    }

    public class Dependencies {
        private final LazyInitEnvRepository lazyEnvironments = new LazyInitEnvRepository();
        @Getter(lazy = true)
        private final EnvironmentRepository environments = initEnvironments();
        @Getter(lazy = true)
        private final ComponentFactory componentFactory = initComponentFactory();
        @Getter(lazy = true)
        private final ConfigTypeRepository configTypeRepository = initConfigTypeRepository();
        @Getter(lazy = true)
        private final PropertiesFactory propertiesFactory = initPropertiesFactory();
        @Getter(lazy = true)
        private final ComponentGraph componentGraph = initComponentGraph();
        @Getter(lazy = true)
        private final Resolver resolver = initResolver();

        private EnvironmentRepository initEnvironments() {
            EnvironmentRepository repo = cache(new FileEnvironmentRepository(
                    rootDir,
                    fsReader,
                    componentFactory(),
                    propertiesFactory())
            );
            lazyEnvironments.setDelegate(repo);
            return repo;
        }

        private ComponentFactory initComponentFactory() {
            return cache(new ComponentFactoryImpl(
                    configTypeRepository(),
                    propertiesFactory()
            ));
        }

        private PropertiesFactory initPropertiesFactory() {
            PropertiesRepository fileRepository = new FilePropertiesRepository(
                    componentGraph(),
                    lazyEnvironments,
                    newConfigIo(fsReader)
            );

            return cache(new PropertiesFactoryImpl(
                    cache(compositeOf(additionalPropertiesRepositories, fileRepository))
            ));
        }

        public Resolver initResolver() {
            return cache(chainOf(
                    initPlaceholderResolver(),
                    new ExpressionResolver()
            ));
        }

        private RecursiveResolver initPlaceholderResolver() {
            Map<String, ComponentProperty> componentSpecialProperties = new ComponentProperties(componentGraph(), environments(), rootDir, destinationDir).get();
            Map<String, EnvProperty> envSpecialProperties = new EnvironmentProperties().get();

            PlaceholderResolveStrategy strategy = cache(composite(join(
                    additionalPlaceholderResolvers,
                    asList(
                            systemPropertiesResolveStrategy(),
                            envVariablesResolveStrategy(),
                            new ComponentResolveStrategy(componentSpecialProperties),
                            new EnvironmentResolveStrategy(environments(), envSpecialProperties),
                            new StandardResolveStrategy(environments())
                    )
            )));

            return new PlaceholderResolver(
                    lazyEnvironments,
                    strategy,
                    joinToSet(componentSpecialProperties.keySet(), envSpecialProperties.keySet())
            );
        }

        private ConfigTypeRepository initConfigTypeRepository() {
            return cache(composite(
                    findDescriptorIn(rootDir, fsReader),
                    new StandardConfigTypeRepository()
            ));
        }

        private ComponentGraph initComponentGraph() {
            ComponentGraph standard = traverseFrom(rootDir);
            return new EnvProfilesComponentGraph(standard, lazyEnvironments);
        }
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/MicroconfigRunner.java
================================================
package io.microconfig.core;

import io.microconfig.core.properties.Properties;
import io.microconfig.core.properties.PropertySerializer;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

import java.io.File;
import java.util.List;

import static io.microconfig.core.Microconfig.searchConfigsIn;
import static io.microconfig.core.configtypes.ConfigTypeFilters.eachConfigType;
import static io.microconfig.core.properties.serializers.PropertySerializers.*;
import static io.microconfig.core.properties.templates.TemplatesService.resolveTemplatesBy;

@Getter
@RequiredArgsConstructor
public class MicroconfigRunner {
    private final Microconfig microconfig;

    public MicroconfigRunner(File rootDir, File destinationDir) {
        this.microconfig = searchConfigsIn(rootDir)
                .withDestinationDir(destinationDir);
    }

    public Properties buildProperties(String env, List<String> groups, List<String> services) {
        return microconfig.inEnvironment(env)
                .findComponentsFrom(groups, services)
                .getPropertiesFor(eachConfigType())
                .resolveBy(microconfig.resolver())
                .forEachComponent(resolveTemplatesBy(microconfig.resolver()));
    }

    public void build(String env, List<String> groups, List<String> services) {
        buildProperties(env, groups, services).save(toFiles());
    }

    public PropertySerializer<File> toFiles() {
        return withLegacySupport(toFileIn(microconfig.destinationDir(), withConfigDiff()),
                microconfig.environments()
        );
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/configtypes/CompositeConfigTypeRepository.java
================================================
package io.microconfig.core.configtypes;

import lombok.RequiredArgsConstructor;

import java.util.List;

import static java.util.Arrays.asList;

@RequiredArgsConstructor
public class CompositeConfigTypeRepository implements ConfigTypeRepository {
    private final List<ConfigTypeRepository> repositories;

    public static ConfigTypeRepository composite(ConfigTypeRepository... repositories) {
        return new CompositeConfigTypeRepository(asList(repositories));
    }

    @Override
    public List<ConfigType> getConfigTypes() {
        return repositories.stream()
                .map(ConfigTypeRepository::getConfigTypes)
                .filter(types -> !types.isEmpty())
                .findFirst()
                .orElseThrow(() -> new IllegalStateException("Config types are not configured"));
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/configtypes/ConfigTypeImpl.java
================================================
package io.microconfig.core.configtypes;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;

import java.util.List;
import java.util.Set;

import static io.microconfig.utils.StreamUtils.filter;
import static java.util.Collections.singleton;

@Getter
@ToString
@RequiredArgsConstructor
public class ConfigTypeImpl implements ConfigType {
    private final String name;
    private final Set<String> sourceExtensions;
    private final String resultFileName;

    public static ConfigType byName(String name) {
        return byNameAndExtensions(name, singleton('.' + name), name);
    }

    public static ConfigType byNameAndExtensions(String name, Set<String> sourceExtensions, String resultFileName) {
        List<String> badExtensions = filter(sourceExtensions, ext -> !ext.startsWith("."));
        if (!badExtensions.isEmpty()) {
            throw new IllegalArgumentException("File extension must start with '.'. Current: " + badExtensions);
        }

        return new ConfigTypeImpl(name, sourceExtensions, resultFileName);
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/configtypes/CustomConfigTypeRepository.java
================================================
package io.microconfig.core.configtypes;

import io.microconfig.io.FsReader;
import lombok.RequiredArgsConstructor;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static io.microconfig.core.configtypes.ConfigTypeImpl.byName;
import static io.microconfig.core.configtypes.ConfigTypeImpl.byNameAndExtensions;
import static io.microconfig.utils.Logger.announce;
import static io.microconfig.utils.StreamUtils.forEach;
import static java.util.Collections.emptyList;
import static java.util.Collections.singleton;

@RequiredArgsConstructor
public class CustomConfigTypeRepository implements ConfigTypeRepository {
    private static final String DESCRIPTOR = "microconfig.yaml";

    private final FsReader fsReader;
    private final File descriptorFile;

    public static ConfigTypeRepository findDescriptorIn(File rootDir, FsReader fsReader) {
        return new CustomConfigTypeRepository(fsReader, new File(rootDir, DESCRIPTOR));
    }

    @Override
    public List<ConfigType> getConfigTypes() {
        if (!descriptorFile.exists()) return emptyList();

        List<ConfigType> types = parseConfigTypes();
        if (!types.isEmpty()) {
            announce("Using settings from " + descriptorFile);
        }
        return types;
    }

    private List<ConfigType> parseConfigTypes() {
        try {
            return new MicroconfigDescriptor(fsReader.readFully(descriptorFile)).getConfigTypes();
        } catch (RuntimeException e) {
            throw new RuntimeException("Can't parse descriptor: " + descriptorFile, e);
        }
    }

    @RequiredArgsConstructor
    private static class MicroconfigDescriptor {
        private static final String CONFIG_TYPES = "configTypes";
        private static final String SOURCE_EXTENSIONS = "sourceExtensions";
        private static final String RESULT_FILE_NAME = "resultFileName";

        private final String content;

        @SuppressWarnings("unchecked")
        private List<ConfigType> getConfigTypes() {
            Map<String, Object> types = new Yaml().load(content);
            List<Object> configTypes = (List<Object>) types.getOrDefault(CONFIG_TYPES, emptyList());
            return forEach(configTypes, this::parse);
        }

        @SuppressWarnings("unchecked")
        private ConfigType parse(Object configTypeObject) {
            if (configTypeObject instanceof String) {
                return byName(configTypeObject.toString());
            }

            Map<String, Object> configType = (Map<String, Object>) configTypeObject;
            String type = configType.keySet().iterator().next();
            Map<String, Object> attributes = (Map<String, Object>) configType.get(type);
            Set<String> sourceExtensions = attributes.containsKey(SOURCE_EXTENSIONS) ? new LinkedHashSet<>((List<String>) attributes.get(SOURCE_EXTENSIONS)) : singleton(type);
            String resultFileName = (String) attributes.getOrDefault(RESULT_FILE_NAME, type);

            return byNameAndExtensions(type, sourceExtensions, resultFileName);
        }
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/configtypes/StandardConfigType.java
================================================
package io.microconfig.core.configtypes;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

import java.util.Set;

import static io.microconfig.utils.CollectionUtils.setOf;

@Getter
@RequiredArgsConstructor
public enum StandardConfigType implements ConfigType {
    APPLICATION("app", setOf(".properties", ".yaml", ".yml"), "application"),
    PROCESS("process", setOf(".process", ".proc"), "process"),
    HELM("helm", setOf(".helm"), "values"),
    DEPLOY("deploy"),
    K8S("k8s"),
    ENV("env"),
    SECRET("secret"),
    LOG4J("log4j"),
    LOG4J2("log4j2");

    private final String name;
    private final Set<String> sourceExtensions;
    private final String resultFileName;

    StandardConfigType(String name) {
        this(name, setOf("." + name), name);
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/configtypes/StandardConfigTypeRepository.java
================================================
package io.microconfig.core.configtypes;

import java.util.List;

import static java.util.Arrays.asList;

public class StandardConfigTypeRepository implements ConfigTypeRepository {
    private final List<ConfigType> standardTypes = asList(StandardConfigType.values());

    @Override
    public List<ConfigType> getConfigTypes() {
        return standardTypes;
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/environments/ComponentFactory.java
================================================
package io.microconfig.core.environments;

public interface ComponentFactory {
    Component createComponent(String name, String type, String environment);
}


================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/environments/ComponentFactoryImpl.java
================================================
package io.microconfig.core.environments;

import io.microconfig.core.configtypes.ConfigTypeRepository;
import io.microconfig.core.properties.PropertiesFactory;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class ComponentFactoryImpl implements ComponentFactory {
    private final ConfigTypeRepository configTypeRepository;
    private final PropertiesFactory propertiesFactory;

    @Override
    public Component createComponent(String componentName,
                                     String componentOriginalName,
                                     String environment) {
        return new ComponentImpl(configTypeRepository, propertiesFactory, componentName, componentOriginalName, environment);
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/environments/ComponentGroupImpl.java
================================================
package io.microconfig.core.environments;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

import java.util.Optional;

import static java.util.Optional.ofNullable;

@RequiredArgsConstructor
public class ComponentGroupImpl implements ComponentGroup {
    @Getter
    private final String name;
    private final String ip;
    @Getter
    private final Components components;

    @Override
    public Optional<String> getIp() {
        return ofNullable(ip);
    }

    @Override
    public Optional<Component> findComponentWithName(String componentName) {
        return components.asList()
                .stream()
                .filter(c -> c.getName().equals(componentName))
                .findFirst();
    }

    @Override
    public String toString() {
        return name + ": " + components;
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/environments/ComponentImpl.java
================================================
package io.microconfig.core.environments;

import io.microconfig.core.configtypes.ConfigType;
import io.microconfig.core.configtypes.ConfigTypeFilter;
import io.microconfig.core.configtypes.ConfigTypeRepository;
import io.microconfig.core.properties.Properties;
import io.microconfig.core.properties.PropertiesFactory;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

import java.util.List;

@EqualsAndHashCode(of = {"name", "originalName", "environment"})
@RequiredArgsConstructor
public class ComponentImpl implements Component {
    private final ConfigTypeRepository configTypeRepository;
    private final PropertiesFactory propertiesFactory;

    @Getter
    private final String name;
    @Getter
    private final String originalName;
    @Getter
    private final String environment;

    @Override
    public Properties getPropertiesFor(ConfigTypeFilter filter) {
        List<ConfigType> filteredTypes = filter.selectTypes(configTypeRepository.getConfigTypes());
        return propertiesFactory.getPropertiesOf(name, originalName, environment, filteredTypes);
    }

    @Override
    public String toString() {
        return name;
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/environments/ComponentsImpl.java
================================================
package io.microconfig.core.environments;

import io.microconfig.core.configtypes.ConfigTypeFilter;
import io.microconfig.core.properties.Properties;
import io.microconfig.core.properties.PropertiesFactory;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;

import java.util.List;

import static io.microconfig.utils.StreamUtils.forEach;

@EqualsAndHashCode
@RequiredArgsConstructor
public class ComponentsImpl implements Components {
    private final List<Component> components;
    private final PropertiesFactory propertiesFactory;

    @Override
    public List<Component> asList() {
        return components;
    }

    @Override
    public Properties getPropertiesFor(ConfigTypeFilter configType) {
        return propertiesFactory.flat(
                forEach(components.parallelStream(), c -> c.getPropertiesFor(configType))
        );
    }

    @Override
    public String toString() {
        return components.toString();
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/environments/EnvironmentImpl.java
================================================
package io.microconfig.core.environments;

import io.microconfig.core.properties.PropertiesFactory;
import io.microconfig.core.properties.repository.ComponentNotFoundException;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.function.Supplier;

import static io.microconfig.utils.Logger.info;
import static io.microconfig.utils.StreamUtils.*;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;

@RequiredArgsConstructor
public class EnvironmentImpl implements Environment {
    @Getter
    private final File source;
    @Getter
    private final String name;
    @Getter
    private final boolean abstractEnv;
    @Getter
    private final int portOffset;
    @Getter
    private final List<String> profiles;
    @Getter
    private final List<ComponentGroup> groups;

    private final ComponentFactory componentFactory;
    private final PropertiesFactory propertiesFactory;

    @Override
    public List<ComponentGroup> findGroupsWithIp(String ip) {
        return filter(groups, g -> g.getIp().filter(ip::equals).isPresent());
    }

    @Override
    public ComponentGroup getGroupWithName(String groupName) {
        return findGroup(group -> group.getName().equals(groupName),
                () -> "groupName=" + groupName);
    }

    @Override
    public Optional<ComponentGroup> findGroupWithComponent(String componentName) {
        return groups.stream()
                .filter(g -> g.findComponentWithName(componentName).isPresent())
                .findFirst();
    }

    @Override
    public Components getAllComponents() {
        List<Component> components = groups.stream()
                .map(ComponentGroup::getComponents)
                .map(Components::asList)
                .flatMap(List::stream)
                .collect(toList());

        return new ComponentsImpl(components, propertiesFactory);
    }

    @Override
    public Component getComponentWithName(String componentName) {
        return findFirstResult(groups, g -> g.findComponentWithName(componentName))
                .orElseThrow(() -> new ComponentNotFoundException(componentName));
    }

    @Override
    public Components findComponentsFrom(List<String> groups, List<String> componentNames) {
        List<Component> componentsFromGroups = componentsFrom(groups);
        List<Component> result = filterBy(componentNames, componentsFromGroups);
        info("Filtered " + result.size() + " component(s) in [" + name + "] env.");
        return new ComponentsImpl(result, propertiesFactory);
    }

    @Override
    public Component findComponentWithName(String componentName) {
        return findFirstResult(groups, g -> g.findComponentWithName(componentName))
                .orElseGet(() -> componentFactory.createComponent(componentName, componentName, name));
    }

    @Override
    public boolean isAbstract() {
        return abstractEnv;
    }

    private List<Component> componentsFrom(List<String> groups) {
        if (groups.isEmpty()) return getAllComponents().asList();

        return groups.stream()
                .map(this::getGroupWithName)
                .map(ComponentGroup::getComponents)
                .map(Components::asList)
                .flatMap(List::stream)
                .collect(toList());
    }

    private List<Component> filterBy(List<String> components, List<Component> componentFromGroups) {
        if (components.isEmpty()) return componentFromGroups;

        Map<String, Component> componentByName = componentFromGroups.stream()
                .collect(toMap(Component::getName, identity()));

        return forEach(components, c -> componentOrEx(componentByName, c));
    }

    private Component componentOrEx(Map<String, Component> componentByName, String component) {
        Component c = componentByName.get(component);
        if (c == null) throw new ComponentNotFoundException(component);
        return c;
    }

    private ComponentGroup findGroup(Predicate<ComponentGroup> groupPredicate,
                                     Supplier<String> description) {
        return groups.stream()
                .filter(groupPredicate)
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException("Can't find group by filter: '" + description.get() + "' in env '" + name + "'"));
    }

    @Override
    public String toString() {
        return name + ": " + groups;
    }
}


================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/environments/repository/ComponentDefinition.java
================================================
package io.microconfig.core.environments.repository;

import io.microconfig.core.environments.Component;
import io.microconfig.core.environments.ComponentFactory;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@EqualsAndHashCode
@RequiredArgsConstructor
class ComponentDefinition {
    @Getter
    private final String name;
    private final String originalName;

    public static ComponentDefinition withAlias(String alias, String originalName) {
        return new ComponentDefinition(alias, originalName);
    }

    public static ComponentDefinition withName(String name) {
        return withAlias(name, name);
    }

    public Component toComponent(ComponentFactory componentFactory, String environment) {
        return componentFactory.createComponent(name, originalName, environment);
    }
}


================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/environments/repository/ComponentGroupDefinition.java
================================================
package io.microconfig.core.environments.repository;

import io.microconfig.core.environments.ComponentFactory;
import io.microconfig.core.environments.ComponentGroup;
import io.microconfig.core.environments.ComponentGroupImpl;
import io.microconfig.core.environments.ComponentsImpl;
import io.microconfig.core.properties.PropertiesFactory;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.With;

import java.util.List;

import static io.microconfig.utils.CollectionUtils.join;
import static io.microconfig.utils.CollectionUtils.minus;
import static io.microconfig.utils.StreamUtils.forEach;
import static java.util.Collections.emptyList;

@With
@RequiredArgsConstructor
class ComponentGroupDefinition {
    @Getter
    private final String name;
    private final String ip;
    @Getter
    private final List<ComponentDefinition> components;

    private final List<ComponentDefinition> excludedComponents;
    private final List<ComponentDefinition> appendedComponents;

    public ComponentGroupDefinition overrideBy(ComponentGroupDefinition override) {
        return getIpFrom(override)
                .getComponentsFrom(override)
                .getExcludedGroupsFrom(override)
                .getAppendedGroupsFrom(override);
    }

    private ComponentGroupDefinition getIpFrom(ComponentGroupDefinition override) {
        return override.ip == null ? this : withIp(override.ip);
    }

    private ComponentGroupDefinition getComponentsFrom(ComponentGroupDefinition override) {
        return override.components.isEmpty() ? this : withComponents(override.components);
    }

    private ComponentGroupDefinition getExcludedGroupsFrom(ComponentGroupDefinition override) {
        return override.excludedComponents.isEmpty() ? this : excludeComponents(override.excludedComponents);
    }

    private ComponentGroupDefinition getAppendedGroupsFrom(ComponentGroupDefinition override) {
        return override.appendedComponents.isEmpty() ? this : joinComponentsWith(override.appendedComponents);
    }

    private ComponentGroupDefinition excludeComponents(List<ComponentDefinition> toExclude) {
        return withComponents(minus(components, toExclude))
                .withExcludedComponents(emptyList());
    }

    private ComponentGroupDefinition joinComponentsWith(List<ComponentDefinition> newAppendedComponents) {
        return withComponents(join(components, newAppendedComponents))
                .withAppendedComponents(emptyList());
    }

    public ComponentGroup toGroup(ComponentFactory componentFactory, PropertiesFactory propertiesFactory, String environment) {
        return new ComponentGroupImpl(
                name,
                ip,
                new ComponentsImpl(
                        forEach(components, c -> c.toComponent(componentFactory, environment)),
                        propertiesFactory
                )
        );
    }
}


================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/environments/repository/EnvInclude.java
================================================
package io.microconfig.core.environments.repository;

import lombok.RequiredArgsConstructor;
import lombok.val;

import java.util.*;
import java.util.function.Function;
import java.util.function.UnaryOperator;
import java.util.stream.Collector;

import static io.microconfig.utils.StreamUtils.*;
import static java.util.Collections.emptySet;
import static java.util.function.Function.identity;

@RequiredArgsConstructor
class EnvInclude {
    private static final EnvInclude empty = new EnvInclude("", emptySet());

    private final String baseEnvironment;
    private final Set<String> excludedGroups;

    public static EnvInclude empty() {
        return empty;
    }

    public EnvironmentDefinition includeTo(EnvironmentDefinition destinationEnv, Function<String, EnvironmentDefinition> repository) {
        val baseGroupByName = findBaseGroupsUsing(repository, destinationEnv);
        forEach(destinationEnv.getGroups(), overrideBaseGroupIn(baseGroupByName).andThen(putOverriddenGroupTo(baseGroupByName)));
        return assignGroupsTo(destinationEnv, baseGroupByName.values());
    }

    private Map<String, ComponentGroupDefinition> findBaseGroupsUsing(Function<String, EnvironmentDefinition> repository, EnvironmentDefinition destinationEnv) {
        EnvironmentDefinition baseEnv = repository.apply(baseEnvironment);
        return forEach(notExcludedGroupsFrom(baseEnv), assignIpOf(destinationEnv), resultsToMap());
    }

    private List<ComponentGroupDefinition> notExcludedGroupsFrom(EnvironmentDefinition baseEnv) {
        return filter(baseEnv.getGroups(), group -> !excludedGroups.contains(group.getName()));
    }

    private UnaryOperator<ComponentGroupDefinition> assignIpOf(EnvironmentDefinition destinationEnv) {
        return group -> destinationEnv.getIp() == null ? group : group.withIp(destinationEnv.getIp());
    }

    private UnaryOperator<ComponentGroupDefinition> overrideBaseGroupIn(Map<String, ComponentGroupDefinition> baseGroupByName) {
        return destinationGroup -> {
            ComponentGroupDefinition baseGroup = baseGroupByName.get(destinationGroup.getName());
            return baseGroup == null ? destinationGroup : baseGroup.overrideBy(destinationGroup);
        };
    }

    private EnvironmentDefinition assignGroupsTo(EnvironmentDefinition destinationEnv, Collection<ComponentGroupDefinition> groups) {
        return destinationEnv.withGroups(new ArrayList<>(groups))
                .withEnvInclude(EnvInclude.empty());
    }

    private Collector<ComponentGroupDefinition, ?, Map<String, ComponentGroupDefinition>> resultsToMap() {
        return toLinkedMap(ComponentGroupDefinition::getName, identity());
    }

    private Function<ComponentGroupDefinition, ComponentGroupDefinition> putOverriddenGroupTo(Map<String, ComponentGroupDefinition> baseGroupByName) {
        return overriddenGroup -> baseGroupByName.put(overriddenGroup.getName(), overriddenGroup);
    }

    public boolean isEmpty() {
        return baseEnvironment.isEmpty();
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/environments/repository/EnvironmentDefinition.java
================================================
package io.microconfig.core.environments.repository;

import io.microconfig.core.environments.ComponentFactory;
import io.microconfig.core.environments.Environment;
import io.microconfig.core.environments.EnvironmentImpl;
import io.microconfig.core.properties.PropertiesFactory;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.With;

import java.io.File;
import java.util.List;
import java.util.Map.Entry;
import java.util.function.Function;

import static io.microconfig.utils.StreamUtils.forEach;
import static java.util.stream.Collectors.*;

@With
@RequiredArgsConstructor
class EnvironmentDefinition {
    private final File source;
    private final String name;
    @Getter
    private final String ip;
    private final boolean abstractEnv;
    private final int portOffset;
    private final List<String> profiles;
    private final EnvInclude envInclude;
    @Getter
    private final List<ComponentGroupDefinition> groups;

    public EnvironmentDefinition processIncludeUsing(Function<String, EnvironmentDefinition> environmentRepository) {
        return envInclude.isEmpty() ? this : envInclude.includeTo(this, environmentRepository);
    }

    public EnvironmentDefinition checkComponentNamesAreUnique() {
        List<String> notUniqueComponents = groups.stream()
                .map(ComponentGroupDefinition::getComponents)
                .flatMap(List::stream)
                .collect(groupingBy(ComponentDefinition::getName, counting()))
                .entrySet().stream()
                .filter(e -> e.getValue() > 1)
                .map(Entry::getKey)
                .collect(toList());

        if (!notUniqueComponents.isEmpty()) {
            throw new IllegalStateException("Environment '" + name + "' contains several declarations of: " + notUniqueComponents);
        }

        return this;
    }

    public Environment toEnvironment(ComponentFactory componentFactory, PropertiesFactory propertiesFactory) {
        return new EnvironmentImpl(
                source,
                name,
                abstractEnv,
                portOffset,
                profiles,
                forEach(groups, g -> g.toGroup(componentFactory, propertiesFactory, name)),
                componentFactory,
                propertiesFactory
        );
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/environments/repository/EnvironmentException.java
================================================
package io.microconfig.core.environments.repository;

import io.microconfig.core.exceptions.MicroconfigException;

import static io.microconfig.utils.StringUtils.getCauseMessage;

public class EnvironmentException extends MicroconfigException {
    public EnvironmentException(String message) {
        super(message);
    }

    public EnvironmentException(String message, Throwable cause) {
        super(message, cause);
    }

    @Override
    public String getMessage() {
        return super.getMessage() + "\n" + getCauseMessage(this);
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/environments/repository/EnvironmentFile.java
================================================
package io.microconfig.core.environments.repository;

import com.google.gson.Gson;
import io.microconfig.io.FsReader;
import lombok.RequiredArgsConstructor;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.util.*;
import java.util.Map.Entry;

import static io.microconfig.core.environments.repository.ComponentDefinition.withAlias;
import static io.microconfig.core.environments.repository.ComponentDefinition.withName;
import static io.microconfig.utils.FileUtils.getName;
import static io.microconfig.utils.StreamUtils.forEach;
import static java.lang.Boolean.TRUE;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;

@RequiredArgsConstructor
class EnvironmentFile {
    private static final String INCLUDE = "include";
    private static final String PROFILES = "profiles";
    private static final String IP = "ip";
    private static final String ABSTRACT = "abstract";
    private static final String PORT_OFFSET = "portOffset";
    private static final String INCLUDE_ENV = "env";
    private static final String EXCLUDE = "exclude";
    private static final String APPEND = "append";
    private static final String COMPONENTS = "components";

    private final File file;

    public EnvironmentDefinition parseUsing(FsReader fsReader) {
        String name = getName(file);
        try {
            return parse(parseToMap(fsReader), name);
        } catch (RuntimeException e) {
            throw new EnvironmentException("Can't parse environment '" + name + "'", e);
        }
    }

    @SuppressWarnings("unchecked")
    private Map<String, Object> parseToMap(FsReader reader) {
        String content = reader.readFully(file);
        return file.getName().endsWith(".json") ?
                new Gson().fromJson(content, Map.class) :
                new Yaml().load(content);
    }

    private EnvironmentDefinition parse(Map<String, Object> keyValue, String name) {
        EnvInclude envInclude = parseInclude(keyValue);
        List<String> profiles = parseProfiles(keyValue);
        int portOffset = parsePortOffset(keyValue);
        String envIp = parseIp(keyValue);
        boolean abstractEnv = parseAbstract(keyValue);
        List<ComponentGroupDefinition> componentGroups = parseComponentGroups(keyValue, envIp);

        return new EnvironmentDefinition(file, name, envIp, abstractEnv, portOffset, profiles, envInclude, componentGroups);
    }

    @SuppressWarnings("unchecked")
    private EnvInclude parseInclude(Map<String, Object> keyValue) {
        Map<String, Object> includeProps = (Map<String, Object>) keyValue.remove(INCLUDE);
        if (includeProps == null) return EnvInclude.empty();

        String name = (String) includeProps.get(INCLUDE_ENV);
        Collection<String> excludes = (Collection<String>) includeProps.getOrDefault(EXCLUDE, emptyList());
        return new EnvInclude(name, new LinkedHashSet<>(excludes));
    }

    private int parsePortOffset(Map<String, ?> keyValue) {
        Number offset = (Number) keyValue.remove(PORT_OFFSET);
        return offset == null ? 0 : offset.intValue();
    }

    private String parseIp(Map<String, ?> keyValue) {
        return (String) keyValue.remove(IP);
    }

    private boolean parseAbstract(Map<String, ?> keyValue) {
        return TRUE == keyValue.remove(ABSTRACT);
    }

    private List<String> parseProfiles(Map<String, Object> keyValue) {
        Object profiles = keyValue.remove(PROFILES);
        if (profiles == null) return emptyList();
        if (profiles instanceof Collection) {
            return ((Collection<?>) profiles)
                    .stream()
                    .map(Object::toString)
                    .collect(toList());
        }
        return singletonList(profiles.toString());
    }

    private List<ComponentGroupDefinition> parseComponentGroups(Map<String, Object> keyValue, String envIp) {
        return forEach(keyValue.entrySet(), groupEntry -> {
            try {
                return parseGroup(groupEntry, envIp);
            } catch (RuntimeException e) {
                throw new EnvironmentException("Can't parse group declaration: '" + groupEntry + "'", e);
            }
        });
    }

    @SuppressWarnings("unchecked")
    private ComponentGroupDefinition parseGroup(Entry<String, Object> componentGroupDeclaration, String envIp) {
        String componentGroupName = componentGroupDeclaration.getKey();
        Map<String, Object> properties = (Map<String, Object>) componentGroupDeclaration.getValue();
        String ip = (String) properties.getOrDefault(IP, envIp);

        List<ComponentDefinition> parsedComponents = parseComponents(properties, COMPONENTS);
        List<ComponentDefinition> excludedComponents = parseComponents(properties, EXCLUDE);
        List<ComponentDefinition> appendedComponents = parseComponents(properties, APPEND);

        return new ComponentGroupDefinition(componentGroupName, ip, parsedComponents, excludedComponents, appendedComponents);
    }

    @SuppressWarnings("unchecked")
    private List<ComponentDefinition> parseComponents(Map<String, Object> keyValue, String property) {
        List<String> values = (List<String>) keyValue.get(property);
        if (values == null) return emptyList();

        return values.stream()
                .filter(Objects::nonNull)
                .map(this::toComponentDefinition)
                .collect(toList());
    }

    private ComponentDefinition toComponentDefinition(String s) {
        String[] parts = s.split(":");
        if (parts.length > 2) {
            throw new IllegalArgumentException("Incorrect component declaration: " + s);
        }
        return parts.length == 1 ? withName(parts[0]) : withAlias(parts[0], parts[1]);
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/environments/repository/FileEnvironmentRepository.java
================================================
package io.microconfig.core.environments.repository;

import io.microconfig.core.environments.ComponentFactory;
import io.microconfig.core.environments.Environment;
import io.microconfig.core.environments.EnvironmentImpl;
import io.microconfig.core.environments.EnvironmentRepository;
import io.microconfig.core.properties.PropertiesFactory;
import io.microconfig.io.FsReader;
import io.microconfig.utils.FileUtils;

import java.io.File;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Stream;

import static io.microconfig.utils.FileUtils.getName;
import static io.microconfig.utils.FileUtils.walk;
import static io.microconfig.utils.StreamUtils.*;
import static java.util.Collections.emptyList;
import static java.util.Optional.empty;
import static java.util.Optional.of;
import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toList;

public class FileEnvironmentRepository implements EnvironmentRepository {
    public static final String ENV_DIR = "envs";

    private final File envDir;
    private final FsReader fsReader;
    private final ComponentFactory componentFactory;
    private final PropertiesFactory propertiesFactory;

    public FileEnvironmentRepository(File rootDir, FsReader fsReader,
                                     ComponentFactory componentFactory, PropertiesFactory propertiesFactory) {
        this.envDir = new File(rootDir, ENV_DIR);
        this.propertiesFactory = propertiesFactory;
        if (!envDir.exists()) {
            throw new IllegalArgumentException("'" + ENV_DIR + "' directory doesn't exist: " + envDir);
        }
        this.fsReader = fsReader;
        this.componentFactory = componentFactory;
    }

    @Override
    public List<Environment> environments() {
        List<Environment> all = forEach(environmentFiles(), parse());
        return filter(all, not(Environment::isAbstract));
    }

    @Override
    public Set<String> environmentNames() {
        return forEach(environments(), Environment::getName, toCollection(TreeSet::new));
    }

    @Override
    public Environment getByName(String name) {
        return findEnvWith(name).orElseThrow(notFoundException(name));
    }

    @Override
    public Environment getOrCreateByName(String name) {
        return findEnvWith(name).orElseGet(fakeEnvWith(name));
    }

    private Optional<Environment> findEnvWith(String name) {
        return envFileWith(name).map(parse());
    }

    private Optional<File> envFileWith(String name) {
        List<File> envFiles = filter(environmentFiles(), withFileName(name));
        if (envFiles.size() > 1) {
            throw new EnvironmentException("Found several env files with name: " + name);
        }
        return envFiles.isEmpty() ? empty() : of(envFiles.get(0));
    }

    private List<File> environmentFiles() {
        try (Stream<Path> stream = walk(envDir.toPath())) {
            return stream.map(Path::toFile)
                    .filter(hasSupportedExtension())
                    .collect(toList());
        }
    }

    private Function<File, Environment> parse() {
        return parseDefinition()
                .andThen(def -> def.toEnvironment(componentFactory, propertiesFactory));
    }

    private Function<File, EnvironmentDefinition> parseDefinition() {
        return f -> new EnvironmentFile(f)
                .parseUsing(fsReader)
                .processIncludeUsing(definitionRepository())
                .checkComponentNamesAreUnique();
    }

    private Function<String, EnvironmentDefinition> definitionRepository() {
        return name -> envFileWith(name)
                .map(parseDefinition())
                .orElseThrow(notFoundException(name));
    }

    private Predicate<File> hasSupportedExtension() {
        return f -> {
            String name = f.getName();
            return name.endsWith(".yaml") || name.endsWith(".json");
        };
    }

    private Predicate<File> withFileName(String envName) {
        return f -> getName(f).equals(envName);
    }

    private Supplier<EnvironmentException> notFoundException(String name) {
        return () -> new EnvironmentException("Can't find env '" + name + "'. Available env files: " + envFileNames());
    }

    private Supplier<Environment> fakeEnvWith(String name) {
        return () -> new EnvironmentImpl(null, name, false, 0, emptyList(), emptyList(), componentFactory, propertiesFactory);
    }

    //prints env names, to avoid StackOverflowError if env can't be parsed
    private Set<String> envFileNames() {
        return forEach(environmentFiles(), FileUtils::getName, toCollection(TreeSet::new));
    }
}


================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/environments/repository/LazyInitEnvRepository.java
================================================
package io.microconfig.core.environments.repository;

import io.microconfig.core.environments.EnvironmentRepository;
import lombok.Setter;
import lombok.experimental.Delegate;

public class LazyInitEnvRepository implements EnvironmentRepository {
    @Setter
    @Delegate
    private EnvironmentRepository delegate;
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/DeclaringComponentImpl.java
================================================
package io.microconfig.core.properties;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@EqualsAndHashCode
@RequiredArgsConstructor
public class DeclaringComponentImpl implements DeclaringComponent {
    private final String configType;
    private final String component;
    private final String environment;

    public static DeclaringComponent copyOf(DeclaringComponent c) {
        return c instanceof DeclaringComponentImpl ? c : new DeclaringComponentImpl(c.getConfigType(), c.getComponent(), c.getEnvironment());
    }

    @Override
    public String toString() {
        return component + "[" + environment + "]";
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/FileBasedComponent.java
================================================
package io.microconfig.core.properties;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

import java.io.File;

import static io.microconfig.utils.StringUtils.unixLikePath;

@Getter
@EqualsAndHashCode
@RequiredArgsConstructor
public class FileBasedComponent implements DeclaringComponent {
    private final File source;
    private final int lineNumber; //starts from 0
    private final boolean yaml;
    private final String configType;
    private final String environment;

    public static FileBasedComponent fileSource(File file, int lineNumber, boolean yaml,
                                                String configType, String environment) {
        return new FileBasedComponent(file, lineNumber, yaml, configType, environment);
    }

    @Override
    public String getComponent() {
        return source.getParentFile().getName();
    }

    @Override
    public String toString() {
        return relativeSource() + ":" + (lineNumber + 1);
    }

    private String relativeSource() {
        String path = unixLikePath(source.toString());
        int rootIndex = path.indexOf("/components/");
        return rootIndex < 0 ? path : ".." + path.substring(rootIndex);
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/OverrideProperty.java
================================================
package io.microconfig.core.properties;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

import static lombok.AccessLevel.PRIVATE;

@RequiredArgsConstructor(access = PRIVATE)
@EqualsAndHashCode
public class OverrideProperty implements Property {
    private static final String MULTI_VAR_PREFIX = "@var.";

    @Getter
    private final String environment;
    private final Property delegate;

    public static boolean isOverrideProperty(String line) {
        return line.startsWith(".@") || line.startsWith("@") || line.startsWith("+");
    }

    public static Property overrideProperty(String key, String value, ConfigFormat configFormat, DeclaringComponent source) {
        boolean isVar = key.startsWith("@") || key.startsWith(".@");
        int offset = key.indexOf('.', 1);
        String envName = extractEnv(key, offset);
        String adjustedKey = key.substring(offset + 1);
        Property delegate = new PropertyImpl(adjustedKey, value, isVar, configFormat, source);
        return new OverrideProperty(envName, delegate);
    }

    private static String extractEnv(String key, int offset) {
        int atOffset = key.indexOf('@');
        int start = atOffset < 0 ? 1 : atOffset + 1;
        return key.startsWith(MULTI_VAR_PREFIX) ? null : key.substring(start, offset);
    }

    @Override
    public String getKey() {
        return delegate.getKey();
    }

    @Override
    public String getValue() {
        return delegate.getValue();
    }

    @Override
    public boolean isVar() {
        return delegate.isVar();
    }

    @Override
    public ConfigFormat getConfigFormat() {
        return delegate.getConfigFormat();
    }

    @Override
    public DeclaringComponent getDeclaringComponent() {
        return delegate.getDeclaringComponent();
    }

    @Override
    public Property resolveBy(Resolver resolver, DeclaringComponent root) {
        return delegate.resolveBy(resolver, root);
    }
}


================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/PropertiesFactoryImpl.java
================================================
package io.microconfig.core.properties;

import io.microconfig.core.configtypes.ConfigType;
import lombok.RequiredArgsConstructor;

import java.util.List;
import java.util.Map;
import java.util.function.Function;

import static io.microconfig.utils.StreamUtils.forEach;
import static java.util.Collections.emptyList;

@RequiredArgsConstructor
public class PropertiesFactoryImpl implements PropertiesFactory {
    private final PropertiesRepository propertiesRepository;

    @Override
    public Properties getPropertiesOf(String componentName,
                                      String componentOriginalName,
                                      String environment,
                                      List<ConfigType> configTypes) {
        return new PropertiesImpl(
                forEach(configTypes, readConfigsFor(componentName, componentOriginalName, environment))
        );
    }

    @Override
    public Properties flat(List<Properties> properties) {
        return PropertiesImpl.flat(properties);
    }

    private Function<ConfigType, TypedProperties> readConfigsFor(String componentName, String componentOriginalName, String environment) {
        return configType -> {
            Map<String, Property> properties = propertiesRepository.getPropertiesOf(componentOriginalName, environment, configType);
            return new TypedPropertiesImpl(configType, componentName, environment, properties, emptyList());
        };
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/PropertiesImpl.java
================================================
package io.microconfig.core.properties;

import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;

import static io.microconfig.utils.StreamUtils.*;
import static java.util.function.Function.identity;

@EqualsAndHashCode
@RequiredArgsConstructor
public class PropertiesImpl implements Properties {
    private final List<TypedProperties> properties;

    public static Properties flat(List<Properties> properties) {
        return new PropertiesImpl(flatMapEach(properties, Properties::asTypedProperties));
    }

    @Override
    public Properties resolveBy(Resolver resolver) {
        return withEachComponent(c -> c.resolveBy(resolver));
    }

    @Override
    public Properties withoutVars() {
        return withEachComponent(TypedProperties::withoutVars);
    }

    @Override
    public Properties without(Predicate<Property> excluded) {
        return withEachComponent(c -> c.without(excluded));
    }

    @Override
    public Properties withPrefix(String prefix) {
        return withEachComponent(tp -> tp.withPrefix(prefix));
    }

    @Override
    public Map<String, Property> getPropertiesAsMap() {
        return propertyKeyTo(identity());
    }

    @Override
    public Map<String, String> getPropertiesAsKeyValue() {
        return propertyKeyTo(Property::getValue);
    }

    @Override
    public Collection<Property> getProperties() {
        return flatMapEach(properties, TypedProperties::getProperties);
    }

    @Override
    public Optional<Property> getPropertyWithKey(String key) {
        return findFirstResult(properties, p -> p.getPropertyWithKey(key));
    }

    @Override
    public <T> List<T> save(PropertySerializer<T> serializer) {
        return forEach(properties, p -> p.save(serializer));
    }

    @Override
    public List<TypedProperties> asTypedProperties() {
        return properties;
    }

    @Override
    public TypedProperties first() {
        return properties.get(0);
    }

    @Override
    public Properties forEachComponent(UnaryOperator<TypedProperties> callback) {
        return withEachComponent(callback);
    }

    private Properties withEachComponent(UnaryOperator<TypedProperties> applyFunction) {
        return new PropertiesImpl(forEach(properties.parallelStream(), applyFunction));
    }

    private <T> Map<String, T> propertyKeyTo(Function<Property, T> valueGetter) {
        return properties.stream()
                .map(TypedProperties::getProperties)
                .flatMap(Collection::stream)
                .collect(toLinkedMap(Property::getKey, valueGetter));
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/PropertiesRepository.java
================================================
package io.microconfig.core.properties;

import io.microconfig.core.configtypes.ConfigType;

import java.util.Map;

public interface PropertiesRepository {
    Map<String, Property> getPropertiesOf(String originalComponentName,
                                          String environment,
                                          ConfigType configType);
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/PropertyImpl.java
================================================
package io.microconfig.core.properties;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.With;

import static io.microconfig.utils.StringUtils.findFirstIndexIn;
import static lombok.AccessLevel.PACKAGE;
import static lombok.AccessLevel.PRIVATE;

@Getter
@EqualsAndHashCode
@RequiredArgsConstructor(access = PACKAGE)
public class PropertyImpl implements Property {
    private static final String TEMP_VALUE = "#var ";

    private final String key;
    @With(PRIVATE)
    private final String value;
    private final boolean var;
    private final ConfigFormat configFormat;

    private final DeclaringComponent declaringComponent;

    public static Property parse(String keyValue, ConfigFormat configFormat, DeclaringComponent source) {
        boolean temp = isTempProperty(keyValue);
        int separatorIndex = findSeparatorIndexIn(keyValue);
        if (separatorIndex < 0) {
            throw new IllegalArgumentException("Incorrect delimiter in '" + keyValue + "' in '" + source +
                    "'\nProperty must contain ':' or '=' as delimiter.");
        }

        String key = keyValue.substring(temp ? TEMP_VALUE.length() : 0, separatorIndex).trim();
        String value = keyValue.substring(separatorIndex + 1).trim();

        return new PropertyImpl(key, value, temp, configFormat, source);
    }

    public static Property property(String key, String value, ConfigFormat configFormat, DeclaringComponent source) {
        return new PropertyImpl(key, value, false, configFormat, source);
    }

    public static Property varProperty(String key, String value, ConfigFormat configFormat, DeclaringComponent source) {
        return new PropertyImpl(key, value, true, configFormat, source);
    }

    public static int findSeparatorIndexIn(String keyValue) {
        return findFirstIndexIn(keyValue, ":=");
    }

    public static boolean isComment(String line) {
        return line.startsWith("#");
    }

    public static boolean isTempProperty(String line) {
        return line.startsWith(TEMP_VALUE);
    }

    @Override
    public Property resolveBy(Resolver resolver, DeclaringComponent root) {
        try {
            String resolved = resolver.resolve(value, declaringComponent, root);
            return withValue(resolved);
        } catch (ResolveException e) {
            e.setProperty(this);
            throw e;
        }
    }

    @Override
    public String toString() {
        return (var ? "#" : "") + key + "=" + value;
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/ResolveException.java
================================================
package io.microconfig.core.properties;

import io.microconfig.core.exceptions.MicroconfigException;
import lombok.Setter;

import static io.microconfig.utils.StringUtils.getCauseMessage;
import static java.util.Optional.ofNullable;

public class ResolveException extends MicroconfigException {
    private final DeclaringComponent current;
    private final DeclaringComponent root;
    @Setter
    private Property property;

    public ResolveException(DeclaringComponent current, DeclaringComponent root, String message) {
        super(message);
        this.root = root;
        this.current = current;
        this.property = null;
    }

    public ResolveException(DeclaringComponent current, DeclaringComponent root, String message, Throwable cause) {
        super(message, cause);
        this.root = root;
        this.current = current;
        this.property = null;
    }

    @Override
    public String getMessage() {
        return rootComponentInfo() + problemInfo();
    }

    private String problemInfo() {
        return exceptionInfo() + super.getMessage() + "\n" + causeMessage();
    }

    private String rootComponentInfo() {
        return "Can't build configs for root component '" + root + "'.\n";
    }

    private String exceptionInfo() {
        return "Exception in\n" +
                "\t" + current + "'\n" +
                propertyMessage();
    }

    private String propertyMessage() {
        return ofNullable(property)
                .map(p -> "\t" + p + "\n")
                .orElse("");
    }

    private String causeMessage() {
        if (getCause() instanceof ResolveException) {
            return "Cause: " + ((ResolveException) getCause()).problemInfo();
        }
        return getCauseMessage(this);
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/TypedPropertiesImpl.java
================================================
package io.microconfig.core.properties;

import io.microconfig.core.configtypes.ConfigType;
import io.microconfig.core.properties.io.yaml.YamlTreeImpl;
import io.microconfig.core.templates.Template;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.With;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import java.util.stream.Collector;

import static io.microconfig.core.properties.ConfigFormat.YAML;
import static io.microconfig.core.properties.PropertyImpl.property;
import static io.microconfig.utils.StreamUtils.*;
import static java.util.Optional.empty;
import static java.util.Optional.of;
import static java.util.function.Function.identity;
import static lombok.AccessLevel.PRIVATE;
import static lombok.AccessLevel.PUBLIC;

@EqualsAndHashCode
@RequiredArgsConstructor
public class TypedPropertiesImpl implements TypedProperties {
    @Getter
    private final ConfigType configType;
    private final String component;
    private final String environment;
    @With(PRIVATE)
    private final Map<String, Property> propertyByKey;
    @With(PUBLIC)
    private final List<Template> templates;

    @Override
    public DeclaringComponent getDeclaringComponent() {
        return new DeclaringComponentImpl(configType.getName(), component, environment);
    }

    @Override
    public TypedProperties resolveBy(Resolver resolver) {
        return withPropertyByKey(
                forEach(propertyByKey.values(), resolveUsing(resolver), toPropertyMap())
        );
    }

    @Override
    public TypedProperties withoutVars() {
        return without(Property::isVar);
    }

    @Override
    public TypedProperties without(Predicate<Property> excluded) {
        return withProperties(excluded.negate());
    }

    @Override
    public TypedProperties withPrefix(String prefix) {
        return withProperties(p -> p.getKey().startsWith(prefix));
    }

    @Override
    public Map<String, Property> getPropertiesAsMap() {
        return propertyByKey;
    }

    @Override
    public Map<String, String> getPropertiesAsKeyValue() {
        return propertyByKey.values()
                .stream()
                .collect(toLinkedMap(Property::getKey, Property::getValue));
    }

    @Override
    public Collection<Property> getProperties() {
        return propertyByKey.values();
    }

    @Override
    public Optional<Property> getPropertyWithKey(String key) {
        Property property = propertyByKey.get(key);
        return property != null ? of(property) : tryFindByPrefix(key);
    }

    @Override
    public <T> T save(PropertySerializer<T> serializer) {
        return serializer.serialize(propertyByKey.values(), templates, configType, component, environment);
    }

    private TypedProperties withProperties(Predicate<Property> filter) {
        return withPropertyByKey(filter(propertyByKey.values(), filter, toPropertyMap()));
    }

    @Override
    public String toString() {
        return getDeclaringComponent().toString();
    }

    private UnaryOperator<Property> resolveUsing(Resolver resolver) {
        DeclaringComponent root = getDeclaringComponent();
        return property -> property.resolveBy(resolver, root);
    }

    private Collector<Property, ?, Map<String, Property>> toPropertyMap() {
        return toLinkedMap(Property::getKey, identity());
    }

    private Optional<Property> tryFindByPrefix(String originalKey) {
        if (!originalKey.endsWith(".*")) return empty();

        String key = originalKey.substring(0, originalKey.length() - 2);
        Collection<Property> withPrefix = withPrefix(key).getProperties();
        if (withPrefix.isEmpty()) return empty();

        return of(property(key, toYaml(withPrefix, key), YAML, getDeclaringComponent()));
    }

    private String toYaml(Collection<Property> withPrefix, String key) {
        Map<String, String> yaml = withPrefix.stream()
                .collect(toLinkedMap(property -> property.getKey().substring(key.length() + 1), Property::getValue));
        return new YamlTreeImpl(false).toYaml(yaml);
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/AbstractConfigReader.java
================================================
package io.microconfig.core.properties.io;

import io.microconfig.core.properties.Property;
import io.microconfig.io.FsReader;
import lombok.RequiredArgsConstructor;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import static io.microconfig.core.properties.PropertyImpl.isComment;
import static io.microconfig.utils.StreamUtils.toSortedMap;

@RequiredArgsConstructor
public abstract class AbstractConfigReader implements ConfigReader {
    protected final File file;
    protected final List<String> lines;

    protected AbstractConfigReader(File file, FsReader fsReader) {
        this(file, fsReader.readLines(file));
    }

    @Override
    public Map<String, String> propertiesAsMap() {
        return properties("", "").stream()
                .collect(toSortedMap(Property::getKey, Property::getValue));
    }

    @Override
    public Map<Integer, String> commentsByLineNumber() {
        Map<Integer, String> result = new TreeMap<>();
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i).trim();
            if (!isComment(line)) continue;

            result.put(i, line);
        }
        return result;
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/ConfigIo.java
================================================
package io.microconfig.core.properties.io;

import java.io.File;

public interface ConfigIo {
    ConfigReader readFrom(File file);

    ConfigWriter writeTo(File file);
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/ConfigReader.java
================================================
package io.microconfig.core.properties.io;

import io.microconfig.core.properties.Property;

import java.util.List;
import java.util.Map;

public interface ConfigReader {
    List<Property> properties(String configType, String environment);

    Map<String, String> propertiesAsMap();

    Map<Integer, String> commentsByLineNumber();
}


================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/ConfigWriter.java
================================================
package io.microconfig.core.properties.io;

import io.microconfig.core.properties.Property;

import java.util.Collection;
import java.util.Map;

public interface ConfigWriter {
    void write(Map<String, String> properties);

    void write(Collection<Property> properties);

    String serialize(Collection<Property> properties);
}


================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/properties/PropertiesConfigIo.java
================================================
package io.microconfig.core.properties.io.properties;

import io.microconfig.core.properties.io.ConfigIo;
import io.microconfig.core.properties.io.ConfigReader;
import io.microconfig.core.properties.io.ConfigWriter;
import io.microconfig.io.FsReader;
import lombok.RequiredArgsConstructor;

import java.io.File;

@RequiredArgsConstructor
public class PropertiesConfigIo implements ConfigIo {
    private final FsReader fileFsReader;

    @Override
    public ConfigReader readFrom(File file) {
        return new PropertiesReader(file, fileFsReader);
    }

    @Override
    public ConfigWriter writeTo(File file) {
        return new PropertiesWriter(file);
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/properties/PropertiesReader.java
================================================
package io.microconfig.core.properties.io.properties;

import io.microconfig.core.properties.Property;
import io.microconfig.core.properties.io.AbstractConfigReader;
import io.microconfig.io.FsReader;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import static io.microconfig.core.properties.ConfigFormat.PROPERTIES;
import static io.microconfig.core.properties.FileBasedComponent.fileSource;
import static io.microconfig.core.properties.PropertyImpl.isComment;
import static io.microconfig.core.properties.PropertyImpl.parse;
import static io.microconfig.utils.FileUtils.LINES_SEPARATOR;

class PropertiesReader extends AbstractConfigReader {
    PropertiesReader(File file, FsReader fileFsReader) {
        super(file, fileFsReader);
    }

    @Override
    public List<Property> properties(String configType, String environment) {
        List<Property> result = new ArrayList<>();

        StringBuilder currentLine = new StringBuilder();
        for (int lineNumber = 0; lineNumber < lines.size(); lineNumber++) {
            String line = lines.get(lineNumber);
            String trimmed = line.trim();
            if (trimmed.isEmpty() || isComment(trimmed)) continue;

            currentLine.append(trimmed);
            if (isMultilineValue(trimmed)) {
                currentLine.append(LINES_SEPARATOR);
                continue;
            }

            Property property = parse(currentLine.toString(), PROPERTIES,
                    fileSource(file, lineNumber, false, configType, environment)
            );
            result.add(property);
            currentLine.setLength(0);
        }

        return result;
    }

    private boolean isMultilineValue(String line) {
        return line.endsWith("\\");
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/properties/PropertiesWriter.java
================================================
package io.microconfig.core.properties.io.properties;

import io.microconfig.core.properties.Property;
import io.microconfig.core.properties.io.ConfigWriter;
import io.microconfig.utils.FileUtils;
import lombok.RequiredArgsConstructor;

import java.io.File;
import java.nio.file.OpenOption;
import java.util.Collection;
import java.util.Map;

import static io.microconfig.utils.FileUtils.LINES_SEPARATOR;
import static java.util.stream.Collectors.joining;

@RequiredArgsConstructor
class PropertiesWriter implements ConfigWriter {
    private final File file;

    @Override
    public void write(Map<String, String> properties) {
        doWrite(serializeMap(properties));
    }

    @Override
    public void write(Collection<Property> properties) {
        doWrite(serialize(properties));
    }

    @Override
    public String serialize(Collection<Property> properties) {
        return properties.stream()
                .filter(p -> !p.isVar())
                .map(Property::toString)
                .collect(joining(LINES_SEPARATOR));
    }

    private String serializeMap(Map<String, String> properties) {
        return properties.entrySet()
                .stream()
                .map(e -> e.getKey() + "=" + e.getValue())
                .collect(joining(LINES_SEPARATOR));
    }

    private void doWrite(String lines, OpenOption... openOptions) {
        FileUtils.write(file.toPath(), lines, openOptions);
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/selector/ConfigFormatDetector.java
================================================
package io.microconfig.core.properties.io.selector;

import io.microconfig.core.properties.ConfigFormat;

import java.io.File;

public interface ConfigFormatDetector {
    ConfigFormat detectConfigFormat(File file);
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/selector/ConfigFormatDetectorImpl.java
================================================
package io.microconfig.core.properties.io.selector;

import io.microconfig.core.properties.ConfigFormat;
import io.microconfig.io.FsReader;
import lombok.RequiredArgsConstructor;

import java.io.File;
import java.util.function.Predicate;

import static io.microconfig.core.properties.ConfigFormat.PROPERTIES;
import static io.microconfig.core.properties.ConfigFormat.YAML;
import static io.microconfig.core.properties.PropertyImpl.findSeparatorIndexIn;
import static io.microconfig.core.properties.PropertyImpl.isComment;


@RequiredArgsConstructor
public class ConfigFormatDetectorImpl implements ConfigFormatDetector {
    private final FsReader reader;

    @Override
    public ConfigFormat detectConfigFormat(File file) {
        if (file.getName().endsWith(PROPERTIES.extension())) return PROPERTIES;
        if (file.getName().endsWith(YAML.extension())) return YAML;
        return hasYamlOffsets(file) ? YAML : PROPERTIES;
    }

    private boolean hasYamlOffsets(File file) {
        if (!file.exists()) return false;

        String firstProperty = reader.firstLineOf(file, withValue()).orElse(null);
        if (firstProperty == null) return false;

        int separatorIndex = findSeparatorIndexIn(firstProperty);
        if (separatorIndex < 0) {
            throw new IllegalArgumentException("Incorrect property " + firstProperty + " in " + file);
        }

        return firstProperty.charAt(separatorIndex) == ':';
    }

    private Predicate<String> withValue() {
        return line -> {
            String trimmed = line.trim();
            return !trimmed.isEmpty() && !isComment(trimmed);
        };
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/selector/ConfigIoFactory.java
================================================
package io.microconfig.core.properties.io.selector;

import io.microconfig.core.properties.io.ConfigIo;
import io.microconfig.core.properties.io.properties.PropertiesConfigIo;
import io.microconfig.core.properties.io.yaml.YamlConfigIo;
import io.microconfig.io.DumpedFsReader;
import io.microconfig.io.FsReader;

import static io.microconfig.utils.CacheProxy.cache;

public class ConfigIoFactory {
    private static final ConfigIo configIo = newConfigIo(new DumpedFsReader());

    public static ConfigIo configIo() {
        return configIo;
    }

    public static ConfigIo newConfigIo(FsReader fsReader) {
        return new ConfigIoSelector(
                cache(new ConfigFormatDetectorImpl(fsReader)),
                new YamlConfigIo(fsReader),
                new PropertiesConfigIo(fsReader)
        );
    }
}


================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/selector/ConfigIoSelector.java
================================================
package io.microconfig.core.properties.io.selector;

import io.microconfig.core.properties.ConfigFormat;
import io.microconfig.core.properties.io.ConfigIo;
import io.microconfig.core.properties.io.ConfigReader;
import io.microconfig.core.properties.io.ConfigWriter;
import lombok.RequiredArgsConstructor;

import java.io.File;

import static io.microconfig.core.properties.ConfigFormat.PROPERTIES;
import static io.microconfig.core.properties.ConfigFormat.YAML;

@RequiredArgsConstructor
public class ConfigIoSelector implements ConfigIo {
    private final ConfigFormatDetector configFormatDetector;

    private final ConfigIo yamlFormat;
    private final ConfigIo propertiesFormat;

    @Override
    public ConfigReader readFrom(File file) {
        return select(file).readFrom(file);
    }

    @Override
    public ConfigWriter writeTo(File file) {
        return select(file).writeTo(file);
    }

    private ConfigIo select(File file) {
        ConfigFormat format = configFormatDetector.detectConfigFormat(file);
        if (format == YAML) return yamlFormat;
        if (format == PROPERTIES) return propertiesFormat;

        throw new IllegalStateException("Unsupported format " + format + " for " + file);
    }
}

================================================
FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/yaml/YamlConfigIo.java
================================================
package io.microconfig.core.properties.io.yaml;

import io.microconfig.core.properties.io.ConfigIo;
import io.microconfig.core.properties.io.ConfigReader;
import io.microconfig.core.properties.io.ConfigWriter;
import io.microconfig.io.FsReader;
import lombok.RequiredArgsConstructor;

import java.io.File;

@RequiredArgsConstructor
public class YamlConfigIo implements ConfigIo {
    private final FsReader fileFsReader;

    @Override
    public ConfigReader readFrom(File file) {
        return new YamlReader(f
Download .txt
gitextract_ljxcps6x/

├── .github/
│   ├── scripts/
│   │   ├── decrypt_secring.sh
│   │   ├── native/
│   │   │   ├── Dockerfile-alpine
│   │   │   ├── graalvm-linux.sh
│   │   │   ├── graalvm-mac.sh
│   │   │   ├── graalvm-win.sh
│   │   │   ├── native.bat
│   │   │   └── native.sh
│   │   └── set_gradle_properties.sh
│   └── workflows/
│       ├── build.yml
│       ├── gradlepublish.yml
│       └── release.yml
├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── agent.sh
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── lib.gradle
├── lombok.config
├── microconfig-api/
│   ├── build.gradle
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── io/
│       │           └── microconfig/
│       │               └── core/
│       │                   ├── configtypes/
│       │                   │   ├── ConfigType.java
│       │                   │   ├── ConfigTypeFilter.java
│       │                   │   ├── ConfigTypeFilters.java
│       │                   │   └── ConfigTypeRepository.java
│       │                   ├── environments/
│       │                   │   ├── Component.java
│       │                   │   ├── ComponentGroup.java
│       │                   │   ├── Components.java
│       │                   │   ├── Environment.java
│       │                   │   └── EnvironmentRepository.java
│       │                   ├── exceptions/
│       │                   │   └── MicroconfigException.java
│       │                   ├── properties/
│       │                   │   ├── ConfigFormat.java
│       │                   │   ├── DeclaringComponent.java
│       │                   │   ├── PlaceholderResolveStrategy.java
│       │                   │   ├── Properties.java
│       │                   │   ├── PropertiesFactory.java
│       │                   │   ├── Property.java
│       │                   │   ├── PropertySerializer.java
│       │                   │   ├── Resolver.java
│       │                   │   └── TypedProperties.java
│       │                   └── templates/
│       │                       └── Template.java
│       └── test/
│           └── java/
│               └── io/
│                   └── microconfig/
│                       └── core/
│                           ├── configtypes/
│                           │   └── ConfigTypeFiltersTest.java
│                           └── properties/
│                               └── ConfigFormatTest.java
├── microconfig-cli/
│   ├── build.gradle
│   └── src/
│       ├── main/
│       │   ├── java/
│       │   │   └── io/
│       │   │       └── microconfig/
│       │   │           ├── CommandLineParamParser.java
│       │   │           ├── MicroconfigMain.java
│       │   │           └── MicroconfigParams.java
│       │   └── resources/
│       │       ├── META-INF/
│       │       │   └── native-image/
│       │       │       ├── jni-config.json
│       │       │       ├── native-image.properties
│       │       │       ├── proxy-config.json
│       │       │       ├── reflect-config.json
│       │       │       └── resource-config.json
│       │       └── log4j2.xml
│       └── test/
│           ├── java/
│           │   └── io/
│           │       └── microconfig/
│           │           ├── CommandLineParamParserTest.java
│           │           ├── MicroconfigMainTest.java
│           │           └── MicroconfigParamsTest.java
│           └── resources/
│               └── repo/
│                   ├── components/
│                   │   └── component/
│                   │       ├── application.yaml
│                   │       └── os.deploy
│                   └── envs/
│                       ├── env1.yaml
│                       ├── env2.yaml
│                       └── env3.yaml
├── microconfig-core/
│   ├── build.gradle
│   └── src/
│       ├── main/
│       │   └── java/
│       │       └── io/
│       │           └── microconfig/
│       │               └── core/
│       │                   ├── Microconfig.java
│       │                   ├── MicroconfigRunner.java
│       │                   ├── configtypes/
│       │                   │   ├── CompositeConfigTypeRepository.java
│       │                   │   ├── ConfigTypeImpl.java
│       │                   │   ├── CustomConfigTypeRepository.java
│       │                   │   ├── StandardConfigType.java
│       │                   │   └── StandardConfigTypeRepository.java
│       │                   ├── environments/
│       │                   │   ├── ComponentFactory.java
│       │                   │   ├── ComponentFactoryImpl.java
│       │                   │   ├── ComponentGroupImpl.java
│       │                   │   ├── ComponentImpl.java
│       │                   │   ├── ComponentsImpl.java
│       │                   │   ├── EnvironmentImpl.java
│       │                   │   └── repository/
│       │                   │       ├── ComponentDefinition.java
│       │                   │       ├── ComponentGroupDefinition.java
│       │                   │       ├── EnvInclude.java
│       │                   │       ├── EnvironmentDefinition.java
│       │                   │       ├── EnvironmentException.java
│       │                   │       ├── EnvironmentFile.java
│       │                   │       ├── FileEnvironmentRepository.java
│       │                   │       └── LazyInitEnvRepository.java
│       │                   └── properties/
│       │                       ├── DeclaringComponentImpl.java
│       │                       ├── FileBasedComponent.java
│       │                       ├── OverrideProperty.java
│       │                       ├── PropertiesFactoryImpl.java
│       │                       ├── PropertiesImpl.java
│       │                       ├── PropertiesRepository.java
│       │                       ├── PropertyImpl.java
│       │                       ├── ResolveException.java
│       │                       ├── TypedPropertiesImpl.java
│       │                       ├── io/
│       │                       │   ├── AbstractConfigReader.java
│       │                       │   ├── ConfigIo.java
│       │                       │   ├── ConfigReader.java
│       │                       │   ├── ConfigWriter.java
│       │                       │   ├── properties/
│       │                       │   │   ├── PropertiesConfigIo.java
│       │                       │   │   ├── PropertiesReader.java
│       │                       │   │   └── PropertiesWriter.java
│       │                       │   ├── selector/
│       │                       │   │   ├── ConfigFormatDetector.java
│       │                       │   │   ├── ConfigFormatDetectorImpl.java
│       │                       │   │   ├── ConfigIoFactory.java
│       │                       │   │   └── ConfigIoSelector.java
│       │                       │   └── yaml/
│       │                       │       ├── YamlConfigIo.java
│       │                       │       ├── YamlReader.java
│       │                       │       ├── YamlTree.java
│       │                       │       ├── YamlTreeImpl.java
│       │                       │       └── YamlWriter.java
│       │                       ├── repository/
│       │                       │   ├── ComponentGraph.java
│       │                       │   ├── ComponentGraphImpl.java
│       │                       │   ├── ComponentNotFoundException.java
│       │                       │   ├── CompositePropertiesRepository.java
│       │                       │   ├── ConfigFile.java
│       │                       │   ├── EnvProfilesComponentGraph.java
│       │                       │   ├── FilePropertiesRepository.java
│       │                       │   ├── Include.java
│       │                       │   ├── Includes.java
│       │                       │   └── RawConfig.java
│       │                       ├── resolvers/
│       │                       │   ├── ChainedResolver.java
│       │                       │   ├── RecursiveResolver.java
│       │                       │   ├── expression/
│       │                       │   │   ├── ExpressionEvaluator.java
│       │                       │   │   ├── ExpressionResolver.java
│       │                       │   │   └── functions/
│       │                       │   │       ├── CustomIoApi.java
│       │                       │   │       └── CustomStringApi.java
│       │                       │   └── placeholder/
│       │                       │       ├── Placeholder.java
│       │                       │       ├── PlaceholderBorders.java
│       │                       │       ├── PlaceholderResolver.java
│       │                       │       └── strategies/
│       │                       │           ├── component/
│       │                       │           │   ├── ComponentProperty.java
│       │                       │           │   ├── ComponentResolveStrategy.java
│       │                       │           │   └── properties/
│       │                       │           │       ├── ComponentProperties.java
│       │                       │           │       ├── ConfigDirProperty.java
│       │                       │           │       ├── ConfigRootDirProperty.java
│       │                       │           │       ├── NameProperty.java
│       │                       │           │       └── ResultDirProperty.java
│       │                       │           ├── composite/
│       │                       │           │   └── CompositeResolveStrategy.java
│       │                       │           ├── environment/
│       │                       │           │   ├── EnvProperty.java
│       │                       │           │   ├── EnvironmentResolveStrategy.java
│       │                       │           │   └── properties/
│       │                       │           │       ├── ComponentOrderProperty.java
│       │                       │           │       ├── EnvNameProperty.java
│       │                       │           │       ├── EnvironmentProperties.java
│       │                       │           │       ├── GroupNameProperty.java
│       │                       │           │       ├── IpProperty.java
│       │                       │           │       └── PortOffsetProperty.java
│       │                       │           ├── standard/
│       │                       │           │   └── StandardResolveStrategy.java
│       │                       │           └── system/
│       │                       │               └── SystemResolveStrategy.java
│       │                       ├── serializers/
│       │                       │   ├── ConfigDiff.java
│       │                       │   ├── ConfigResult.java
│       │                       │   └── PropertySerializers.java
│       │                       └── templates/
│       │                           ├── BinaryTemplate.java
│       │                           ├── MustacheTemplateProcessor.java
│       │                           ├── StringTemplate.java
│       │                           ├── TemplateContentPostProcessor.java
│       │                           ├── TemplateDefinition.java
│       │                           ├── TemplateDefinitionParser.java
│       │                           ├── TemplatePattern.java
│       │                           ├── TemplatesService.java
│       │                           └── definition/
│       │                               └── parser/
│       │                                   ├── ArrowNotationParser.java
│       │                                   ├── FromToNotationParser.java
│       │                                   └── SquareBracketsNotationParser.java
│       └── test/
│           ├── java/
│           │   └── io/
│           │       └── microconfig/
│           │           └── core/
│           │               ├── ClasspathReader.java
│           │               ├── MicroconfigRunnerTest.java
│           │               ├── MicroconfigTest.java
│           │               ├── TemplatesTest.java
│           │               ├── configtypes/
│           │               │   ├── CompositeConfigTypeRepositoryTest.java
│           │               │   ├── ConfigTypeImplTest.java
│           │               │   ├── CustomConfigTypeRepositoryTest.java
│           │               │   ├── StandardConfigTypeRepositoryTest.java
│           │               │   └── StandardConfigTypeTest.java
│           │               ├── environments/
│           │               │   ├── ComponentFactoryImplTest.java
│           │               │   ├── ComponentGroupImplTest.java
│           │               │   ├── ComponentImplTest.java
│           │               │   ├── ComponentsImplTest.java
│           │               │   ├── EnvironmentImplTest.java
│           │               │   └── repository/
│           │               │       ├── ComponentDefinitionTest.java
│           │               │       └── FileEnvironmentRepositoryTest.java
│           │               └── properties/
│           │                   ├── ComponentWithEnvTest.java
│           │                   ├── FileBasedComponentTest.java
│           │                   ├── PropertiesImplTest.java
│           │                   ├── PropertyImplTest.java
│           │                   ├── ResolveExceptionTest.java
│           │                   ├── TypedPropertiesImplTest.java
│           │                   ├── io/
│           │                   │   ├── properties/
│           │                   │   │   └── PropertiesConfigIoTest.java
│           │                   │   └── yaml/
│           │                   │       ├── YamlConfigIoTest.java
│           │                   │       └── YamlTreeImplTest.java
│           │                   ├── repository/
│           │                   │   ├── ComponentNotFoundExceptionTest.java
│           │                   │   ├── CompositePropertiesRepositoryTest.java
│           │                   │   ├── EnvProfilesComponentGraphTest.java
│           │                   │   └── IncludeTest.java
│           │                   ├── resolvers/
│           │                   │   ├── expression/
│           │                   │   │   ├── ExpressionResolverTest.java
│           │                   │   │   └── functions/
│           │                   │   │       └── CustomStringApiTest.java
│           │                   │   └── placeholder/
│           │                   │       └── PlaceholderBordersTest.java
│           │                   └── templates/
│           │                       ├── StringTemplatePatternTest.java
│           │                       ├── StringTemplateTest.java
│           │                       └── definition/
│           │                           └── parser/
│           │                               ├── ArrowNotationParserTest.java
│           │                               ├── FromToNotationParserTest.java
│           │                               └── SquareBracketsNotationParserTest.java
│           └── resources/
│               ├── configFormats/
│               │   ├── properties/
│               │   │   └── propLine.properties
│               │   └── yaml/
│               │       ├── list/
│               │       │   ├── list.yaml
│               │       │   └── resultList.yaml
│               │       ├── parse/
│               │       │   ├── inner.yaml
│               │       │   ├── inner2.yaml
│               │       │   ├── mapLikeName.yaml
│               │       │   ├── multilines.yaml
│               │       │   └── simple.yaml
│               │       ├── sortOrder/
│               │       │   ├── initial.yaml
│               │       │   └── result.yaml
│               │       └── tree/
│               │           ├── doubleEscapedResult.yaml
│               │           └── escapedResult.yaml
│               ├── configTypes/
│               │   └── microconfig.yaml
│               ├── envs/
│               │   ├── bad/
│               │   │   └── envs/
│               │   │       ├── bad.json
│               │   │       ├── bad.yaml
│               │   │       ├── bad2.yaml
│               │   │       ├── badGroup.yaml
│               │   │       ├── copy.yaml
│               │   │       └── subfolder/
│               │   │           └── bad2.yaml
│               │   └── good/
│               │       └── envs/
│               │           ├── alias.yaml
│               │           ├── base.yaml
│               │           ├── dev.yaml
│               │           ├── folder/
│               │           │   ├── prod.yaml
│               │           │   └── staging.yaml
│               │           └── test.yaml
│               ├── repo/
│               │   ├── components/
│               │   │   ├── aliases/
│               │   │   │   ├── node/
│               │   │   │   │   ├── expect.aliases
│               │   │   │   │   ├── expect.aliases.node1
│               │   │   │   │   ├── expect.aliases.node3
│               │   │   │   │   └── service.properties
│               │   │   │   ├── placeholderToAlias/
│               │   │   │   │   ├── expect.aliases
│               │   │   │   │   └── service.properties
│               │   │   │   └── placeholderToAliasWithAnotherTipe/
│               │   │   │       ├── aliasType/
│               │   │   │       │   ├── expect.aliases
│               │   │   │       │   └── service.properties
│               │   │   │       └── aliasType2/
│               │   │   │           ├── service.process
│               │   │   │           └── service.properties
│               │   │   ├── configType/
│               │   │   │   ├── appType/
│               │   │   │   │   ├── application.yaml
│               │   │   │   │   └── expect.dev
│               │   │   │   ├── application.process
│               │   │   │   ├── application.yaml
│               │   │   │   ├── expect.dev
│               │   │   │   └── processType/
│               │   │   │       └── application.process
│               │   │   ├── doubleQuatesWithKey/
│               │   │   │   ├── application.yaml
│               │   │   │   └── expect.env
│               │   │   ├── empty/
│               │   │   │   ├── expect.uat
│               │   │   │   └── service.properties
│               │   │   ├── envChange/
│               │   │   │   ├── 01/
│               │   │   │   │   ├── include-client/
│               │   │   │   │   │   ├── application.yaml
│               │   │   │   │   │   ├── expect.dev
│               │   │   │   │   │   └── expect.uat1
│               │   │   │   │   ├── include-client2/
│               │   │   │   │   │   ├── application.uat1.yaml
│               │   │   │   │   │   ├── application.yaml
│               │   │   │   │   │   ├── expect.dev
│               │   │   │   │   │   └── expect.uat1
│               │   │   │   │   └── includeOtherEnv/
│               │   │   │   │       ├── application.yaml
│               │   │   │   │       ├── expect.dev
│               │   │   │   │       └── expect.uat1
│               │   │   │   ├── contextChange/
│               │   │   │   │   ├── application.dev.yaml
│               │   │   │   │   ├── application.prod.yaml
│               │   │   │   │   ├── application.test.yaml
│               │   │   │   │   ├── application.yaml
│               │   │   │   │   ├── expect.dev
│               │   │   │   │   └── expect.uat
│               │   │   │   ├── envInFile/
│               │   │   │   │   ├── application.prod.yaml
│               │   │   │   │   ├── application.yaml
│               │   │   │   │   ├── expect.prod-a
│               │   │   │   │   └── expect.prod-b
│               │   │   │   ├── envInclude/
│               │   │   │   │   └── application.yaml
│               │   │   │   ├── profiles/
│               │   │   │   │   ├── prof1/
│               │   │   │   │   │   ├── application.yaml
│               │   │   │   │   │   └── expect.profs
│               │   │   │   │   └── prof2/
│               │   │   │   │       ├── application.LONG.yaml
│               │   │   │   │       └── application.yaml
│               │   │   │   └── transitiveEnvChange/
│               │   │   │       ├── tec01/
│               │   │   │       │   ├── application.yaml
│               │   │   │       │   ├── expect.dev
│               │   │   │       │   └── expect.prod
│               │   │   │       ├── tec02/
│               │   │   │       │   └── application.yaml
│               │   │   │       ├── tec03/
│               │   │   │       │   └── application.yaml
│               │   │   │       └── tec04/
│               │   │   │           ├── application.dev.yaml
│               │   │   │           ├── application.prod.yaml
│               │   │   │           └── application.yaml
│               │   │   ├── envIpTest/
│               │   │   │   ├── ip1/
│               │   │   │   │   ├── expect.uat
│               │   │   │   │   └── service.properties
│               │   │   │   └── ip2/
│               │   │   │       ├── expect.uat
│               │   │   │       └── service.properties
│               │   │   ├── envProps/
│               │   │   │   ├── expect.uat
│               │   │   │   └── service.properties
│               │   │   ├── exceptions/
│               │   │   │   ├── IncludeBad/
│               │   │   │   │   ├── includeBadDelimiter/
│               │   │   │   │   │   ├── application.prop.properties
│               │   │   │   │   │   ├── application.yl.yaml
│               │   │   │   │   │   ├── exception.prop
│               │   │   │   │   │   └── exception.yl
│               │   │   │   │   ├── includeBadEnv/
│               │   │   │   │   │   ├── application.includeNotUniqueComponents.yaml
│               │   │   │   │   │   ├── application.includeParseError.yaml
│               │   │   │   │   │   ├── exception.includeNotUniqueComponents
│               │   │   │   │   │   └── truncate.includeParseError
│               │   │   │   │   ├── includeBadExpression/
│               │   │   │   │   │   ├── application.yaml
│               │   │   │   │   │   └── exception.dev
│               │   │   │   │   ├── includeBadInclude/
│               │   │   │   │   │   ├── application.yaml
│               │   │   │   │   │   └── exception.dev
│               │   │   │   │   └── includeBadPlaceholder/
│               │   │   │   │       ├── application.component.yaml
│               │   │   │   │       ├── application.key.yaml
│               │   │   │   │       ├── exception.component
│               │   │   │   │       └── exception.key
│               │   │   │   ├── bad/
│               │   │   │   │   ├── badDelimiter/
│               │   │   │   │   │   ├── application.prop.properties
│               │   │   │   │   │   ├── application.yl.yaml
│               │   │   │   │   │   ├── exception.prop
│               │   │   │   │   │   └── exception.yl
│               │   │   │   │   ├── badEnv/
│               │   │   │   │   │   ├── application.yaml
│               │   │   │   │   │   ├── exception.notUniqueComponents
│               │   │   │   │   │   └── truncate.parseError
│               │   │   │   │   ├── badExpression/
│               │   │   │   │   │   ├── application.yaml
│               │   │   │   │   │   └── exception.dev
│               │   │   │   │   ├── badInclude/
│               │   │   │   │   │   ├── application.yaml
│               │   │   │   │   │   └── exception.dev
│               │   │   │   │   ├── badPlaceholder/
│               │   │   │   │   │   ├── application.component.yaml
│               │   │   │   │   │   ├── application.key.yaml
│               │   │   │   │   │   ├── exception.component
│               │   │   │   │   │   └── exception.key
│               │   │   │   │   └── cyclic/
│               │   │   │   │       ├── cyclicDetect/
│               │   │   │   │       │   ├── exception.dev
│               │   │   │   │       │   └── service.properties
│               │   │   │   │       └── cyclicDetectBetweenConfigTypes/
│               │   │   │   │           ├── exception.dev
│               │   │   │   │           ├── process.process
│               │   │   │   │           └── service.properties
│               │   │   │   └── placeholderToBad/
│               │   │   │       ├── placeholderToBadDelimiter/
│               │   │   │       │   ├── application.prop.properties
│               │   │   │       │   ├── application.yl.yaml
│               │   │   │       │   ├── exception.prop
│               │   │   │       │   └── exception.yl
│               │   │   │       ├── placeholderToBadEnv/
│               │   │   │       │   ├── application.notUniqueComponents.yaml
│               │   │   │       │   ├── application.parseError.yaml
│               │   │   │       │   ├── exception.notUniqueComponents
│               │   │   │       │   └── trunc.parseError
│               │   │   │       ├── placeholderToBadExpression/
│               │   │   │       │   ├── application.yaml
│               │   │   │       │   └── exception.dev
│               │   │   │       ├── placeholderToBadInclude/
│               │   │   │       │   ├── application.yaml
│               │   │   │       │   └── exception.dev
│               │   │   │       └── placeholderToBadPlaceholder/
│               │   │   │           ├── application.component.yaml
│               │   │   │           ├── application.key.yaml
│               │   │   │           ├── exception.component
│               │   │   │           └── exception.key
│               │   │   ├── ignore/
│               │   │   │   ├── ignored/
│               │   │   │   │   ├── expect.uat
│               │   │   │   │   └── service.properties
│               │   │   │   ├── notIgnored/
│               │   │   │   │   ├── expect.uat
│               │   │   │   │   └── service.properties
│               │   │   │   └── notIgnored2/
│               │   │   │       ├── expect.uat
│               │   │   │       └── service.properties
│               │   │   ├── includeDefault/
│               │   │   │   ├── id-default/
│               │   │   │   │   ├── application.dev.yaml
│               │   │   │   │   ├── application.yaml
│               │   │   │   │   ├── expect.dev
│               │   │   │   │   └── expect.test
│               │   │   │   ├── id-middle/
│               │   │   │   │   ├── application.yaml
│               │   │   │   │   ├── expect.dev
│               │   │   │   │   └── expect.test
│               │   │   │   └── id-root/
│               │   │   │       ├── application.yaml
│               │   │   │       ├── expect.dev
│               │   │   │       └── expect.test
│               │   │   ├── includeTest/
│               │   │   │   ├── cyclicInclude/
│               │   │   │   │   ├── ci1/
│               │   │   │   │   │   ├── expect.uat
│               │   │   │   │   │   └── service.properties
│               │   │   │   │   └── ci2/
│               │   │   │   │       ├── expect.uat
│               │   │   │   │       └── service.properties
│               │   │   │   ├── includeOrder/
│               │   │   │   │   ├── inOrder1/
│               │   │   │   │   │   ├── expect.dev
│               │   │   │   │   │   ├── expect.uat
│               │   │   │   │   │   ├── service.dev.properties
│               │   │   │   │   │   └── service.uat.properties
│               │   │   │   │   ├── inOrder2/
│               │   │   │   │   │   ├── expect.some
│               │   │   │   │   │   └── service.properties
│               │   │   │   │   └── inOrder3/
│               │   │   │   │       ├── expect.some
│               │   │   │   │       └── service.properties
│               │   │   │   ├── includeWithEnvChange/
│               │   │   │   │   ├── ic1/
│               │   │   │   │   │   ├── expect.dev
│               │   │   │   │   │   └── service.dev.properties
│               │   │   │   │   ├── ic2/
│               │   │   │   │   │   ├── expect.dev
│               │   │   │   │   │   └── service.dev.properties
│               │   │   │   │   ├── ic3/
│               │   │   │   │   │   ├── expect.dev
│               │   │   │   │   │   ├── expect.dev2
│               │   │   │   │   │   ├── service.dev.properties
│               │   │   │   │   │   └── service.dev2.properties
│               │   │   │   │   ├── ic4/
│               │   │   │   │   │   ├── expect.dev
│               │   │   │   │   │   ├── service.dev.properties
│               │   │   │   │   │   └── service.dev2.properties
│               │   │   │   │   └── ic5/
│               │   │   │   │       ├── expect.dev
│               │   │   │   │       └── service.properties
│               │   │   │   └── simpleInclude/
│               │   │   │       ├── si1/
│               │   │   │       │   ├── expect.uat
│               │   │   │       │   └── service.properties
│               │   │   │       ├── si2/
│               │   │   │       │   ├── expect.uat
│               │   │   │       │   └── service.properties
│               │   │   │       └── si3/
│               │   │   │           ├── expect.uat
│               │   │   │           └── service.properties
│               │   │   ├── linksFromProfiles/
│               │   │   │   ├── includeFromProfile/
│               │   │   │   │   ├── application.profile.yaml
│               │   │   │   │   └── expect.env
│               │   │   │   ├── placeholderFromProfile/
│               │   │   │   │   ├── application.profile.yaml
│               │   │   │   │   └── expect.env
│               │   │   │   └── targetForProfile/
│               │   │   │       ├── application.env.yaml
│               │   │   │       ├── application.profile.yaml
│               │   │   │       ├── expect.env
│               │   │   │       └── expect.profile
│               │   │   ├── mergeLists/
│               │   │   │   ├── application.yaml
│               │   │   │   └── expect.env
│               │   │   ├── multiVar/
│               │   │   │   ├── application.prod.yaml
│               │   │   │   ├── application.yaml
│               │   │   │   └── expect.prod
│               │   │   ├── other/
│               │   │   │   ├── common/
│               │   │   │   │   ├── expect.dev
│               │   │   │   │   └── oracle.properties
│               │   │   │   ├── th/
│               │   │   │   │   ├── nonexists/
│               │   │   │   │   │   └── service.properties
│               │   │   │   │   ├── th-client/
│               │   │   │   │   │   ├── java.proc
│               │   │   │   │   │   ├── service.properties
│               │   │   │   │   │   └── service.uat.properties
│               │   │   │   │   └── th-server/
│               │   │   │   │       ├── arg.proc
│               │   │   │   │       ├── service.demo.properties
│               │   │   │   │       ├── service.properties
│               │   │   │   │       └── service.uat.properties
│               │   │   │   └── zeus/
│               │   │   │       ├── expect.demo
│               │   │   │       ├── expect.some
│               │   │   │       ├── expect.uat
│               │   │   │       ├── service.demo.properties
│               │   │   │       ├── service.properties
│               │   │   │       └── service.uat.properties
│               │   │   ├── placeholderAsDefaultValue/
│               │   │   │   ├── appication.yaml
│               │   │   │   └── expect.placeholderAsDefaultValue
│               │   │   ├── placeholderOverride/
│               │   │   │   ├── placeholderOverride1/
│               │   │   │   │   ├── appication.yaml
│               │   │   │   │   └── expect.dev
│               │   │   │   └── placeholderOverride2/
│               │   │   │       ├── appication.dev2.yaml
│               │   │   │       ├── appication.yaml
│               │   │   │       └── expect.dev
│               │   │   ├── placeholderToMap/
│               │   │   │   ├── 2expect.nextLevel
│               │   │   │   ├── 2expect.sameLevel
│               │   │   │   ├── appication.nextLevel.yaml
│               │   │   │   └── appication.sameLevel.yaml
│               │   │   ├── placeholderToSpel/
│               │   │   │   ├── pts/
│               │   │   │   │   ├── expect.dev
│               │   │   │   │   └── service.properties
│               │   │   │   └── ptsports/
│               │   │   │       ├── expect.dev
│               │   │   │       └── service.properties
│               │   │   ├── portOffsetTest/
│               │   │   │   ├── expect.dev
│               │   │   │   ├── expect.dev2
│               │   │   │   └── service.properties
│               │   │   ├── predefinedFunctions/
│               │   │   │   ├── application.yaml
│               │   │   │   └── expect.dev
│               │   │   ├── profiles/
│               │   │   │   └── profileAndInclude/
│               │   │   │       ├── p_common/
│               │   │   │       │   └── application.yaml
│               │   │   │       ├── p_service/
│               │   │   │       │   ├── application.yaml
│               │   │   │       │   ├── expect.dev_with_profile
│               │   │   │       │   └── expect.test
│               │   │   │       └── p_vars/
│               │   │   │           ├── application.dev_with_profile.yaml
│               │   │   │           ├── application.some.yaml
│               │   │   │           └── application.yaml
│               │   │   ├── selfPlaceholderOverride/
│               │   │   │   ├── scomp1/
│               │   │   │   │   ├── expect.dev
│               │   │   │   │   └── service.properties
│               │   │   │   └── scomp2/
│               │   │   │       ├── expect.dev
│               │   │   │       └── service.properties
│               │   │   ├── similarEnvNamesTest/
│               │   │   │   ├── dependent/
│               │   │   │   │   ├── expect.another-dev
│               │   │   │   │   ├── expect.dev
│               │   │   │   │   ├── expect.some
│               │   │   │   │   ├── expect.z-dev
│               │   │   │   │   ├── service.another-dev.properties
│               │   │   │   │   ├── service.dev.properties
│               │   │   │   │   ├── service.properties
│               │   │   │   │   └── service.z-dev.properties
│               │   │   │   └── main/
│               │   │   │       ├── expect.another-dev
│               │   │   │       ├── expect.dev
│               │   │   │       ├── expect.some
│               │   │   │       ├── expect.z-dev
│               │   │   │       └── service.properties
│               │   │   ├── simple/
│               │   │   │   ├── application.yaml
│               │   │   │   ├── expect.dev
│               │   │   │   └── simple2/
│               │   │   │       └── application.yaml
│               │   │   ├── specialPlaceholders/
│               │   │   │   ├── application.properties
│               │   │   │   ├── expect.special
│               │   │   │   └── expect.special.specialPlaceholders2
│               │   │   ├── spelWrap/
│               │   │   │   ├── expect.dev
│               │   │   │   └── service.properties
│               │   │   ├── thisOverride/
│               │   │   │   ├── tov1/
│               │   │   │   │   ├── expect.uat
│               │   │   │   │   └── service.properties
│               │   │   │   └── tov2/
│               │   │   │       ├── expect.uat
│               │   │   │       └── service.properties
│               │   │   ├── var/
│               │   │   │   ├── expect.dev
│               │   │   │   └── var.properties
│               │   │   ├── yamlLists/
│               │   │   │   ├── application.yaml
│               │   │   │   └── expect.env
│               │   │   └── yamlMultiline/
│               │   │       ├── application.yaml
│               │   │       └── expect.dev
│               │   └── envs/
│               │       ├── abstract.yaml
│               │       ├── aliases.yaml
│               │       ├── bad/
│               │       │   ├── notUniqueComponents.yaml
│               │       │   └── parseError.yaml
│               │       ├── dev.yaml
│               │       ├── dev2.json
│               │       ├── dev_with_profile.yaml
│               │       ├── env.yaml
│               │       ├── p1.json
│               │       ├── prod-a.yaml
│               │       ├── prod-b.yaml
│               │       ├── profs.yaml
│               │       ├── special.yaml
│               │       ├── uat.json
│               │       └── var.json
│               └── templates/
│                   ├── components/
│                   │   └── mustache/
│                   │       ├── application.yaml
│                   │       ├── expect.dev
│                   │       └── template.templ
│                   ├── envs/
│                   │   └── dev.yaml
│                   └── templateWithMultiLines.yaml
├── pomSettings.gradle
├── release.sh
├── secring.gpg.gpg
├── settings.gradle
└── utils/
    └── src/
        ├── main/
        │   └── java/
        │       └── io/
        │           └── microconfig/
        │               ├── io/
        │               │   ├── DumpedFsReader.java
        │               │   └── FsReader.java
        │               └── utils/
        │                   ├── CacheProxy.java
        │                   ├── CollectionUtils.java
        │                   ├── ConsoleColor.java
        │                   ├── FileUtils.java
        │                   ├── IoUtils.java
        │                   ├── Logger.java
        │                   ├── Os.java
        │                   ├── StreamUtils.java
        │                   └── StringUtils.java
        └── test/
            ├── java/
            │   └── io/
            │       └── microconfig/
            │           ├── io/
            │           │   └── DumpedFsReaderTest.java
            │           └── utils/
            │               ├── CacheProxyTest.java
            │               ├── CollectionUtilsTest.java
            │               ├── ConsoleColorTest.java
            │               ├── FileUtilsTest.java
            │               ├── IoUtilsTest.java
            │               ├── StreamUtilsTest.java
            │               └── StringUtilsTest.java
            └── resources/
                └── file.yaml
Download .txt
SYMBOL INDEX (1058 symbols across 181 files)

FILE: microconfig-api/src/main/java/io/microconfig/core/configtypes/ConfigType.java
  type ConfigType (line 5) | public interface ConfigType {
    method getName (line 6) | String getName();
    method getSourceExtensions (line 8) | Set<String> getSourceExtensions();
    method getResultFileName (line 10) | String getResultFileName();

FILE: microconfig-api/src/main/java/io/microconfig/core/configtypes/ConfigTypeFilter.java
  type ConfigTypeFilter (line 5) | public interface ConfigTypeFilter {
    method selectTypes (line 6) | List<ConfigType> selectTypes(List<ConfigType> supportedTypes);

FILE: microconfig-api/src/main/java/io/microconfig/core/configtypes/ConfigTypeFilters.java
  class ConfigTypeFilters (line 17) | @RequiredArgsConstructor(access = PRIVATE)
    method eachConfigType (line 19) | public static ConfigTypeFilter eachConfigType() {
    method configType (line 23) | public static ConfigTypeFilter configType(ConfigType... types) {
    method configTypeWithName (line 32) | public static ConfigTypeFilter configTypeWithName(String... name) {
    method configTypeWithExtensionOf (line 43) | public static ConfigTypeFilter configTypeWithExtensionOf(File file) {
    method validateNames (line 55) | private static void validateNames(Set<String> names, List<ConfigType> ...
    method noConfigTypesProvidedException (line 63) | private static IllegalArgumentException noConfigTypesProvidedException...

FILE: microconfig-api/src/main/java/io/microconfig/core/configtypes/ConfigTypeRepository.java
  type ConfigTypeRepository (line 5) | public interface ConfigTypeRepository {
    method getConfigTypes (line 6) | List<ConfigType> getConfigTypes();

FILE: microconfig-api/src/main/java/io/microconfig/core/environments/Component.java
  type Component (line 6) | public interface Component {
    method getName (line 7) | String getName();
    method getOriginalName (line 9) | String getOriginalName();
    method getEnvironment (line 11) | String getEnvironment();
    method getPropertiesFor (line 13) | Properties getPropertiesFor(ConfigTypeFilter filter);

FILE: microconfig-api/src/main/java/io/microconfig/core/environments/ComponentGroup.java
  type ComponentGroup (line 5) | public interface ComponentGroup {
    method getName (line 6) | String getName();
    method getIp (line 8) | Optional<String> getIp();
    method getComponents (line 10) | Components getComponents();
    method findComponentWithName (line 12) | Optional<Component> findComponentWithName(String name);

FILE: microconfig-api/src/main/java/io/microconfig/core/environments/Components.java
  type Components (line 8) | public interface Components {
    method asList (line 9) | List<Component> asList();
    method getPropertiesFor (line 11) | Properties getPropertiesFor(ConfigTypeFilter filter);

FILE: microconfig-api/src/main/java/io/microconfig/core/environments/Environment.java
  type Environment (line 7) | public interface Environment {
    method getName (line 8) | String getName();
    method getSource (line 10) | File getSource();
    method isAbstract (line 12) | boolean isAbstract();
    method getPortOffset (line 14) | int getPortOffset();
    method getProfiles (line 16) | List<String> getProfiles();
    method getGroups (line 18) | List<ComponentGroup> getGroups();
    method findGroupsWithIp (line 20) | List<ComponentGroup> findGroupsWithIp(String ip);
    method getGroupWithName (line 22) | ComponentGroup getGroupWithName(String groupName);
    method findGroupWithComponent (line 24) | Optional<ComponentGroup> findGroupWithComponent(String componentName);
    method getAllComponents (line 26) | Components getAllComponents();
    method getComponentWithName (line 28) | Component getComponentWithName(String componentName);
    method findComponentsFrom (line 30) | Components findComponentsFrom(List<String> groups, List<String> compon...
    method findComponentWithName (line 32) | Component findComponentWithName(String componentName);

FILE: microconfig-api/src/main/java/io/microconfig/core/environments/EnvironmentRepository.java
  type EnvironmentRepository (line 6) | public interface EnvironmentRepository {
    method environments (line 7) | List<Environment> environments();
    method environmentNames (line 9) | Set<String> environmentNames();
    method getByName (line 11) | Environment getByName(String name);
    method getOrCreateByName (line 13) | Environment getOrCreateByName(String name);

FILE: microconfig-api/src/main/java/io/microconfig/core/exceptions/MicroconfigException.java
  class MicroconfigException (line 5) | @NoArgsConstructor
    method MicroconfigException (line 7) | public MicroconfigException(String message) {
    method MicroconfigException (line 11) | public MicroconfigException(String message, Throwable cause) {

FILE: microconfig-api/src/main/java/io/microconfig/core/properties/ConfigFormat.java
  type ConfigFormat (line 3) | public enum ConfigFormat {
    method extension (line 7) | public String extension() {

FILE: microconfig-api/src/main/java/io/microconfig/core/properties/DeclaringComponent.java
  type DeclaringComponent (line 3) | public interface DeclaringComponent {
    method getConfigType (line 4) | String getConfigType();
    method getComponent (line 6) | String getComponent();
    method getEnvironment (line 8) | String getEnvironment();

FILE: microconfig-api/src/main/java/io/microconfig/core/properties/PlaceholderResolveStrategy.java
  type PlaceholderResolveStrategy (line 5) | public interface PlaceholderResolveStrategy {
    method resolve (line 6) | Optional<Property> resolve(String component, String key, String enviro...

FILE: microconfig-api/src/main/java/io/microconfig/core/properties/Properties.java
  type Properties (line 10) | public interface Properties {
    method resolveBy (line 11) | Properties resolveBy(Resolver resolver);
    method withoutVars (line 13) | Properties withoutVars();
    method without (line 15) | Properties without(Predicate<Property> excluded);
    method withPrefix (line 17) | Properties withPrefix(String prefix);
    method getPropertiesAsMap (line 19) | Map<String, Property> getPropertiesAsMap();
    method getPropertiesAsKeyValue (line 21) | Map<String, String> getPropertiesAsKeyValue();
    method getProperties (line 23) | Collection<Property> getProperties();
    method getPropertyWithKey (line 25) | Optional<Property> getPropertyWithKey(String key);
    method save (line 27) | <T> List<T> save(PropertySerializer<T> serializer);
    method asTypedProperties (line 29) | List<TypedProperties> asTypedProperties();
    method forEachComponent (line 31) | Properties forEachComponent(UnaryOperator<TypedProperties> callback);
    method first (line 33) | TypedProperties first();

FILE: microconfig-api/src/main/java/io/microconfig/core/properties/PropertiesFactory.java
  type PropertiesFactory (line 7) | public interface PropertiesFactory {
    method getPropertiesOf (line 8) | Properties getPropertiesOf(String componentName,
    method flat (line 13) | Properties flat(List<Properties> properties);

FILE: microconfig-api/src/main/java/io/microconfig/core/properties/Property.java
  type Property (line 3) | public interface Property {
    method getKey (line 4) | String getKey();
    method getValue (line 6) | String getValue();
    method isVar (line 8) | boolean isVar();
    method getConfigFormat (line 10) | ConfigFormat getConfigFormat();
    method getDeclaringComponent (line 12) | DeclaringComponent getDeclaringComponent();
    method resolveBy (line 14) | Property resolveBy(Resolver resolver, DeclaringComponent root);

FILE: microconfig-api/src/main/java/io/microconfig/core/properties/PropertySerializer.java
  type PropertySerializer (line 9) | public interface PropertySerializer<T> {
    method serialize (line 10) | T serialize(Collection<Property> properties,

FILE: microconfig-api/src/main/java/io/microconfig/core/properties/Resolver.java
  type Resolver (line 3) | public interface Resolver {
    method resolve (line 4) | String resolve(String value, DeclaringComponent sourceOfValue, Declari...

FILE: microconfig-api/src/main/java/io/microconfig/core/properties/TypedProperties.java
  type TypedProperties (line 12) | public interface TypedProperties {
    method getConfigType (line 13) | ConfigType getConfigType();
    method getDeclaringComponent (line 15) | DeclaringComponent getDeclaringComponent();
    method resolveBy (line 17) | TypedProperties resolveBy(Resolver resolver);
    method withoutVars (line 19) | TypedProperties withoutVars();
    method without (line 21) | TypedProperties without(Predicate<Property> excluded);
    method withPrefix (line 23) | TypedProperties withPrefix(String prefix);
    method withTemplates (line 25) | TypedProperties withTemplates(List<Template> templates);
    method getPropertiesAsMap (line 27) | Map<String, Property> getPropertiesAsMap();
    method getPropertiesAsKeyValue (line 29) | Map<String, String> getPropertiesAsKeyValue();
    method getProperties (line 31) | Collection<Property> getProperties();
    method getPropertyWithKey (line 33) | Optional<Property> getPropertyWithKey(String key);
    method save (line 35) | <T> T save(PropertySerializer<T> serializer);

FILE: microconfig-api/src/main/java/io/microconfig/core/templates/Template.java
  type Template (line 5) | public interface Template {
    method getSource (line 6) | File getSource();
    method getDestination (line 8) | File getDestination();
    method getFileName (line 10) | String getFileName();
    method getContent (line 12) | String getContent();
    method getContentAsBytes (line 14) | byte[] getContentAsBytes();

FILE: microconfig-api/src/test/java/io/microconfig/core/configtypes/ConfigTypeFiltersTest.java
  class ConfigTypeFiltersTest (line 17) | class ConfigTypeFiltersTest {
    method selectEachConfigType (line 23) | @Test
    method useProvidedTypes (line 31) | @Test
    method selectByConfigName (line 40) | @Test
    method failOnUnsupportedName (line 48) | @Test
    method failOnEmptyNames (line 53) | @Test
    method selectByFileExtension (line 59) | @Test
    method failOnFileWithoutExtension (line 67) | @Test
    method type (line 73) | private ConfigType type(String name) {

FILE: microconfig-api/src/test/java/io/microconfig/core/properties/ConfigFormatTest.java
  class ConfigFormatTest (line 9) | class ConfigFormatTest {
    method extension (line 10) | @Test

FILE: microconfig-cli/src/main/java/io/microconfig/CommandLineParamParser.java
  class CommandLineParamParser (line 13) | @RequiredArgsConstructor
    method parse (line 17) | public static CommandLineParamParser parse(String... args) {
    method value (line 31) | public String value(String key) {
    method valueOr (line 35) | public String valueOr(String key, String defaultValue) {
    method listValue (line 43) | public List<String> listValue(String key) {
    method requiredValue (line 47) | public String requiredValue(String key, String npeMessage) {
    method printErrorAndExit (line 55) | public static void printErrorAndExit(String npeMessage) {
    method booleanValue (line 60) | public boolean booleanValue(String key) {
    method contains (line 64) | public boolean contains(String key) {

FILE: microconfig-cli/src/main/java/io/microconfig/MicroconfigMain.java
  class MicroconfigMain (line 30) | @RequiredArgsConstructor
    method main (line 41) | public static void main(String... args) {
    method build (line 62) | private void build() {
    method doBuild (line 73) | private void doBuild() {
    method environmentsToBuild (line 89) | private Set<String> environmentsToBuild() {
    method printVersion (line 105) | private static void printVersion() {

FILE: microconfig-cli/src/main/java/io/microconfig/MicroconfigParams.java
  class MicroconfigParams (line 12) | @RequiredArgsConstructor
    method parse (line 16) | public static MicroconfigParams parse(String... args) {
    method rootDir (line 20) | public File rootDir() {
    method destinationDir (line 24) | public String destinationDir() {
    method groups (line 28) | public List<String> groups() {
    method services (line 32) | public List<String> services() {
    method stacktrace (line 36) | public boolean stacktrace() {
    method version (line 40) | public boolean version() {
    method jsonOutput (line 44) | public boolean jsonOutput() {
    method environments (line 48) | public Set<String> environments() {
    method isSingleEnvBuild (line 63) | public boolean isSingleEnvBuild() {

FILE: microconfig-cli/src/test/java/io/microconfig/CommandLineParamParserTest.java
  class CommandLineParamParserTest (line 9) | class CommandLineParamParserTest {
    method parse (line 10) | @Test

FILE: microconfig-cli/src/test/java/io/microconfig/MicroconfigMainTest.java
  class MicroconfigMainTest (line 17) | class MicroconfigMainTest {
    method setup (line 25) | @BeforeEach
    method should_generate_config_for_single_env_when_e_param_given (line 30) | @Test
    method should_generate_config_for_multiple_envs_when_envs_param_given (line 37) | @Test
    method should_generate_config_for_all_envs_when_star_in_envs_list (line 48) | @ParameterizedTest
    method should_not_generate_config_for_excluded_envs (line 59) | @Test
    method escape (line 71) | private String escape(String name) {
    method checkConfigGeneratedFor (line 75) | private void checkConfigGeneratedFor(String component, String nestedDi...
    method checkConfigNotGeneratedFor (line 79) | private void checkConfigNotGeneratedFor(String component, String neste...
    method checkComponentBuildResult (line 83) | private void checkComponentBuildResult(String component, String nested...
    method buildFilePath (line 88) | private String buildFilePath(String component, String fileName, String...
    method checkFileExist (line 96) | private void checkFileExist(String filePath, boolean shouldFileExist) {

FILE: microconfig-cli/src/test/java/io/microconfig/MicroconfigParamsTest.java
  class MicroconfigParamsTest (line 13) | class MicroconfigParamsTest {
    method rootDir (line 26) | @Test
    method destinationDir (line 31) | @Test
    method env (line 37) | @Test
    method envs (line 42) | @Test
    method groups (line 47) | @Test
    method services (line 53) | @Test
    method jsonOutput (line 59) | @Test
    method testVersion (line 65) | @Test
    method isSingleEnvBuild (line 70) | @Test

FILE: microconfig-core/src/main/java/io/microconfig/core/Microconfig.java
  class Microconfig (line 55) | @Accessors(fluent = true)
    method searchConfigsIn (line 71) | public static Microconfig searchConfigsIn(File rootDir) {
    method inEnvironment (line 79) | public Environment inEnvironment(String name) {
    method environments (line 87) | public EnvironmentRepository environments() {
    method resolver (line 91) | public Resolver resolver() {
    method logger (line 95) | public void logger(boolean enabled) {
    class Dependencies (line 99) | public class Dependencies {
      method initEnvironments (line 114) | private EnvironmentRepository initEnvironments() {
      method initComponentFactory (line 125) | private ComponentFactory initComponentFactory() {
      method initPropertiesFactory (line 132) | private PropertiesFactory initPropertiesFactory() {
      method initResolver (line 144) | public Resolver initResolver() {
      method initPlaceholderResolver (line 151) | private RecursiveResolver initPlaceholderResolver() {
      method initConfigTypeRepository (line 173) | private ConfigTypeRepository initConfigTypeRepository() {
      method initComponentGraph (line 180) | private ComponentGraph initComponentGraph() {

FILE: microconfig-core/src/main/java/io/microconfig/core/MicroconfigRunner.java
  class MicroconfigRunner (line 16) | @Getter
    method MicroconfigRunner (line 21) | public MicroconfigRunner(File rootDir, File destinationDir) {
    method buildProperties (line 26) | public Properties buildProperties(String env, List<String> groups, Lis...
    method build (line 34) | public void build(String env, List<String> groups, List<String> servic...
    method toFiles (line 38) | public PropertySerializer<File> toFiles() {

FILE: microconfig-core/src/main/java/io/microconfig/core/configtypes/CompositeConfigTypeRepository.java
  class CompositeConfigTypeRepository (line 9) | @RequiredArgsConstructor
    method composite (line 13) | public static ConfigTypeRepository composite(ConfigTypeRepository... r...
    method getConfigTypes (line 17) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/configtypes/ConfigTypeImpl.java
  class ConfigTypeImpl (line 13) | @Getter
    method byName (line 21) | public static ConfigType byName(String name) {
    method byNameAndExtensions (line 25) | public static ConfigType byNameAndExtensions(String name, Set<String> ...

FILE: microconfig-core/src/main/java/io/microconfig/core/configtypes/CustomConfigTypeRepository.java
  class CustomConfigTypeRepository (line 20) | @RequiredArgsConstructor
    method findDescriptorIn (line 27) | public static ConfigTypeRepository findDescriptorIn(File rootDir, FsRe...
    method getConfigTypes (line 31) | @Override
    method parseConfigTypes (line 42) | private List<ConfigType> parseConfigTypes() {
    class MicroconfigDescriptor (line 50) | @RequiredArgsConstructor
      method getConfigTypes (line 58) | @SuppressWarnings("unchecked")
      method parse (line 65) | @SuppressWarnings("unchecked")

FILE: microconfig-core/src/main/java/io/microconfig/core/configtypes/StandardConfigType.java
  type StandardConfigType (line 10) | @Getter
    method StandardConfigType (line 27) | StandardConfigType(String name) {

FILE: microconfig-core/src/main/java/io/microconfig/core/configtypes/StandardConfigTypeRepository.java
  class StandardConfigTypeRepository (line 7) | public class StandardConfigTypeRepository implements ConfigTypeRepository {
    method getConfigTypes (line 10) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/environments/ComponentFactory.java
  type ComponentFactory (line 3) | public interface ComponentFactory {
    method createComponent (line 4) | Component createComponent(String name, String type, String environment);

FILE: microconfig-core/src/main/java/io/microconfig/core/environments/ComponentFactoryImpl.java
  class ComponentFactoryImpl (line 7) | @RequiredArgsConstructor
    method createComponent (line 12) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/environments/ComponentGroupImpl.java
  class ComponentGroupImpl (line 10) | @RequiredArgsConstructor
    method getIp (line 18) | @Override
    method findComponentWithName (line 23) | @Override
    method toString (line 31) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/environments/ComponentImpl.java
  class ComponentImpl (line 14) | @EqualsAndHashCode(of = {"name", "originalName", "environment"})
    method getPropertiesFor (line 27) | @Override
    method toString (line 33) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/environments/ComponentsImpl.java
  class ComponentsImpl (line 13) | @EqualsAndHashCode
    method asList (line 19) | @Override
    method getPropertiesFor (line 24) | @Override
    method toString (line 31) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/environments/EnvironmentImpl.java
  class EnvironmentImpl (line 21) | @RequiredArgsConstructor
    method findGroupsWithIp (line 39) | @Override
    method getGroupWithName (line 44) | @Override
    method findGroupWithComponent (line 50) | @Override
    method getAllComponents (line 57) | @Override
    method getComponentWithName (line 68) | @Override
    method findComponentsFrom (line 74) | @Override
    method findComponentWithName (line 82) | @Override
    method isAbstract (line 88) | @Override
    method componentsFrom (line 93) | private List<Component> componentsFrom(List<String> groups) {
    method filterBy (line 104) | private List<Component> filterBy(List<String> components, List<Compone...
    method componentOrEx (line 113) | private Component componentOrEx(Map<String, Component> componentByName...
    method findGroup (line 119) | private ComponentGroup findGroup(Predicate<ComponentGroup> groupPredic...
    method toString (line 127) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/environments/repository/ComponentDefinition.java
  class ComponentDefinition (line 9) | @EqualsAndHashCode
    method withAlias (line 16) | public static ComponentDefinition withAlias(String alias, String origi...
    method withName (line 20) | public static ComponentDefinition withName(String name) {
    method toComponent (line 24) | public Component toComponent(ComponentFactory componentFactory, String...

FILE: microconfig-core/src/main/java/io/microconfig/core/environments/repository/ComponentGroupDefinition.java
  class ComponentGroupDefinition (line 19) | @With
    method overrideBy (line 31) | public ComponentGroupDefinition overrideBy(ComponentGroupDefinition ov...
    method getIpFrom (line 38) | private ComponentGroupDefinition getIpFrom(ComponentGroupDefinition ov...
    method getComponentsFrom (line 42) | private ComponentGroupDefinition getComponentsFrom(ComponentGroupDefin...
    method getExcludedGroupsFrom (line 46) | private ComponentGroupDefinition getExcludedGroupsFrom(ComponentGroupD...
    method getAppendedGroupsFrom (line 50) | private ComponentGroupDefinition getAppendedGroupsFrom(ComponentGroupD...
    method excludeComponents (line 54) | private ComponentGroupDefinition excludeComponents(List<ComponentDefin...
    method joinComponentsWith (line 59) | private ComponentGroupDefinition joinComponentsWith(List<ComponentDefi...
    method toGroup (line 64) | public ComponentGroup toGroup(ComponentFactory componentFactory, Prope...

FILE: microconfig-core/src/main/java/io/microconfig/core/environments/repository/EnvInclude.java
  class EnvInclude (line 15) | @RequiredArgsConstructor
    method empty (line 22) | public static EnvInclude empty() {
    method includeTo (line 26) | public EnvironmentDefinition includeTo(EnvironmentDefinition destinati...
    method findBaseGroupsUsing (line 32) | private Map<String, ComponentGroupDefinition> findBaseGroupsUsing(Func...
    method notExcludedGroupsFrom (line 37) | private List<ComponentGroupDefinition> notExcludedGroupsFrom(Environme...
    method assignIpOf (line 41) | private UnaryOperator<ComponentGroupDefinition> assignIpOf(Environment...
    method overrideBaseGroupIn (line 45) | private UnaryOperator<ComponentGroupDefinition> overrideBaseGroupIn(Ma...
    method assignGroupsTo (line 52) | private EnvironmentDefinition assignGroupsTo(EnvironmentDefinition des...
    method resultsToMap (line 57) | private Collector<ComponentGroupDefinition, ?, Map<String, ComponentGr...
    method putOverriddenGroupTo (line 61) | private Function<ComponentGroupDefinition, ComponentGroupDefinition> p...
    method isEmpty (line 65) | public boolean isEmpty() {

FILE: microconfig-core/src/main/java/io/microconfig/core/environments/repository/EnvironmentDefinition.java
  class EnvironmentDefinition (line 19) | @With
    method processIncludeUsing (line 33) | public EnvironmentDefinition processIncludeUsing(Function<String, Envi...
    method checkComponentNamesAreUnique (line 37) | public EnvironmentDefinition checkComponentNamesAreUnique() {
    method toEnvironment (line 54) | public Environment toEnvironment(ComponentFactory componentFactory, Pr...

FILE: microconfig-core/src/main/java/io/microconfig/core/environments/repository/EnvironmentException.java
  class EnvironmentException (line 7) | public class EnvironmentException extends MicroconfigException {
    method EnvironmentException (line 8) | public EnvironmentException(String message) {
    method EnvironmentException (line 12) | public EnvironmentException(String message, Throwable cause) {
    method getMessage (line 16) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/environments/repository/EnvironmentFile.java
  class EnvironmentFile (line 21) | @RequiredArgsConstructor
    method parseUsing (line 35) | public EnvironmentDefinition parseUsing(FsReader fsReader) {
    method parseToMap (line 44) | @SuppressWarnings("unchecked")
    method parse (line 52) | private EnvironmentDefinition parse(Map<String, Object> keyValue, Stri...
    method parseInclude (line 63) | @SuppressWarnings("unchecked")
    method parsePortOffset (line 73) | private int parsePortOffset(Map<String, ?> keyValue) {
    method parseIp (line 78) | private String parseIp(Map<String, ?> keyValue) {
    method parseAbstract (line 82) | private boolean parseAbstract(Map<String, ?> keyValue) {
    method parseProfiles (line 86) | private List<String> parseProfiles(Map<String, Object> keyValue) {
    method parseComponentGroups (line 98) | private List<ComponentGroupDefinition> parseComponentGroups(Map<String...
    method parseGroup (line 108) | @SuppressWarnings("unchecked")
    method parseComponents (line 121) | @SuppressWarnings("unchecked")
    method toComponentDefinition (line 132) | private ComponentDefinition toComponentDefinition(String s) {

FILE: microconfig-core/src/main/java/io/microconfig/core/environments/repository/FileEnvironmentRepository.java
  class FileEnvironmentRepository (line 31) | public class FileEnvironmentRepository implements EnvironmentRepository {
    method FileEnvironmentRepository (line 39) | public FileEnvironmentRepository(File rootDir, FsReader fsReader,
    method environments (line 50) | @Override
    method environmentNames (line 56) | @Override
    method getByName (line 61) | @Override
    method getOrCreateByName (line 66) | @Override
    method findEnvWith (line 71) | private Optional<Environment> findEnvWith(String name) {
    method envFileWith (line 75) | private Optional<File> envFileWith(String name) {
    method environmentFiles (line 83) | private List<File> environmentFiles() {
    method parse (line 91) | private Function<File, Environment> parse() {
    method parseDefinition (line 96) | private Function<File, EnvironmentDefinition> parseDefinition() {
    method definitionRepository (line 103) | private Function<String, EnvironmentDefinition> definitionRepository() {
    method hasSupportedExtension (line 109) | private Predicate<File> hasSupportedExtension() {
    method withFileName (line 116) | private Predicate<File> withFileName(String envName) {
    method notFoundException (line 120) | private Supplier<EnvironmentException> notFoundException(String name) {
    method fakeEnvWith (line 124) | private Supplier<Environment> fakeEnvWith(String name) {
    method envFileNames (line 129) | private Set<String> envFileNames() {

FILE: microconfig-core/src/main/java/io/microconfig/core/environments/repository/LazyInitEnvRepository.java
  class LazyInitEnvRepository (line 7) | public class LazyInitEnvRepository implements EnvironmentRepository {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/DeclaringComponentImpl.java
  class DeclaringComponentImpl (line 7) | @Getter
    method copyOf (line 15) | public static DeclaringComponent copyOf(DeclaringComponent c) {
    method toString (line 19) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/FileBasedComponent.java
  class FileBasedComponent (line 11) | @Getter
    method fileSource (line 21) | public static FileBasedComponent fileSource(File file, int lineNumber,...
    method getComponent (line 26) | @Override
    method toString (line 31) | @Override
    method relativeSource (line 36) | private String relativeSource() {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/OverrideProperty.java
  class OverrideProperty (line 9) | @RequiredArgsConstructor(access = PRIVATE)
    method isOverrideProperty (line 18) | public static boolean isOverrideProperty(String line) {
    method overrideProperty (line 22) | public static Property overrideProperty(String key, String value, Conf...
    method extractEnv (line 31) | private static String extractEnv(String key, int offset) {
    method getKey (line 37) | @Override
    method getValue (line 42) | @Override
    method isVar (line 47) | @Override
    method getConfigFormat (line 52) | @Override
    method getDeclaringComponent (line 57) | @Override
    method resolveBy (line 62) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/PropertiesFactoryImpl.java
  class PropertiesFactoryImpl (line 13) | @RequiredArgsConstructor
    method getPropertiesOf (line 17) | @Override
    method flat (line 27) | @Override
    method readConfigsFor (line 32) | private Function<ConfigType, TypedProperties> readConfigsFor(String co...

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/PropertiesImpl.java
  class PropertiesImpl (line 17) | @EqualsAndHashCode
    method flat (line 22) | public static Properties flat(List<Properties> properties) {
    method resolveBy (line 26) | @Override
    method withoutVars (line 31) | @Override
    method without (line 36) | @Override
    method withPrefix (line 41) | @Override
    method getPropertiesAsMap (line 46) | @Override
    method getPropertiesAsKeyValue (line 51) | @Override
    method getProperties (line 56) | @Override
    method getPropertyWithKey (line 61) | @Override
    method save (line 66) | @Override
    method asTypedProperties (line 71) | @Override
    method first (line 76) | @Override
    method forEachComponent (line 81) | @Override
    method withEachComponent (line 86) | private Properties withEachComponent(UnaryOperator<TypedProperties> ap...
    method propertyKeyTo (line 90) | private <T> Map<String, T> propertyKeyTo(Function<Property, T> valueGe...

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/PropertiesRepository.java
  type PropertiesRepository (line 7) | public interface PropertiesRepository {
    method getPropertiesOf (line 8) | Map<String, Property> getPropertiesOf(String originalComponentName,

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/PropertyImpl.java
  class PropertyImpl (line 12) | @Getter
    method parse (line 26) | public static Property parse(String keyValue, ConfigFormat configForma...
    method property (line 40) | public static Property property(String key, String value, ConfigFormat...
    method varProperty (line 44) | public static Property varProperty(String key, String value, ConfigFor...
    method findSeparatorIndexIn (line 48) | public static int findSeparatorIndexIn(String keyValue) {
    method isComment (line 52) | public static boolean isComment(String line) {
    method isTempProperty (line 56) | public static boolean isTempProperty(String line) {
    method resolveBy (line 60) | @Override
    method toString (line 71) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/ResolveException.java
  class ResolveException (line 9) | public class ResolveException extends MicroconfigException {
    method ResolveException (line 15) | public ResolveException(DeclaringComponent current, DeclaringComponent...
    method ResolveException (line 22) | public ResolveException(DeclaringComponent current, DeclaringComponent...
    method getMessage (line 29) | @Override
    method problemInfo (line 34) | private String problemInfo() {
    method rootComponentInfo (line 38) | private String rootComponentInfo() {
    method exceptionInfo (line 42) | private String exceptionInfo() {
    method propertyMessage (line 48) | private String propertyMessage() {
    method causeMessage (line 54) | private String causeMessage() {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/TypedPropertiesImpl.java
  class TypedPropertiesImpl (line 28) | @EqualsAndHashCode
    method getDeclaringComponent (line 40) | @Override
    method resolveBy (line 45) | @Override
    method withoutVars (line 52) | @Override
    method without (line 57) | @Override
    method withPrefix (line 62) | @Override
    method getPropertiesAsMap (line 67) | @Override
    method getPropertiesAsKeyValue (line 72) | @Override
    method getProperties (line 79) | @Override
    method getPropertyWithKey (line 84) | @Override
    method save (line 90) | @Override
    method withProperties (line 95) | private TypedProperties withProperties(Predicate<Property> filter) {
    method toString (line 99) | @Override
    method resolveUsing (line 104) | private UnaryOperator<Property> resolveUsing(Resolver resolver) {
    method toPropertyMap (line 109) | private Collector<Property, ?, Map<String, Property>> toPropertyMap() {
    method tryFindByPrefix (line 113) | private Optional<Property> tryFindByPrefix(String originalKey) {
    method toYaml (line 123) | private String toYaml(Collection<Property> withPrefix, String key) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/AbstractConfigReader.java
  class AbstractConfigReader (line 15) | @RequiredArgsConstructor
    method AbstractConfigReader (line 20) | protected AbstractConfigReader(File file, FsReader fsReader) {
    method propertiesAsMap (line 24) | @Override
    method commentsByLineNumber (line 30) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/ConfigIo.java
  type ConfigIo (line 5) | public interface ConfigIo {
    method readFrom (line 6) | ConfigReader readFrom(File file);
    method writeTo (line 8) | ConfigWriter writeTo(File file);

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/ConfigReader.java
  type ConfigReader (line 8) | public interface ConfigReader {
    method properties (line 9) | List<Property> properties(String configType, String environment);
    method propertiesAsMap (line 11) | Map<String, String> propertiesAsMap();
    method commentsByLineNumber (line 13) | Map<Integer, String> commentsByLineNumber();

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/ConfigWriter.java
  type ConfigWriter (line 8) | public interface ConfigWriter {
    method write (line 9) | void write(Map<String, String> properties);
    method write (line 11) | void write(Collection<Property> properties);
    method serialize (line 13) | String serialize(Collection<Property> properties);

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/properties/PropertiesConfigIo.java
  class PropertiesConfigIo (line 11) | @RequiredArgsConstructor
    method readFrom (line 15) | @Override
    method writeTo (line 20) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/properties/PropertiesReader.java
  class PropertiesReader (line 17) | class PropertiesReader extends AbstractConfigReader {
    method PropertiesReader (line 18) | PropertiesReader(File file, FsReader fileFsReader) {
    method properties (line 22) | @Override
    method isMultilineValue (line 48) | private boolean isMultilineValue(String line) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/properties/PropertiesWriter.java
  class PropertiesWriter (line 16) | @RequiredArgsConstructor
    method write (line 20) | @Override
    method write (line 25) | @Override
    method serialize (line 30) | @Override
    method serializeMap (line 38) | private String serializeMap(Map<String, String> properties) {
    method doWrite (line 45) | private void doWrite(String lines, OpenOption... openOptions) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/selector/ConfigFormatDetector.java
  type ConfigFormatDetector (line 7) | public interface ConfigFormatDetector {
    method detectConfigFormat (line 8) | ConfigFormat detectConfigFormat(File file);

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/selector/ConfigFormatDetectorImpl.java
  class ConfigFormatDetectorImpl (line 16) | @RequiredArgsConstructor
    method detectConfigFormat (line 20) | @Override
    method hasYamlOffsets (line 27) | private boolean hasYamlOffsets(File file) {
    method withValue (line 41) | private Predicate<String> withValue() {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/selector/ConfigIoFactory.java
  class ConfigIoFactory (line 11) | public class ConfigIoFactory {
    method configIo (line 14) | public static ConfigIo configIo() {
    method newConfigIo (line 18) | public static ConfigIo newConfigIo(FsReader fsReader) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/selector/ConfigIoSelector.java
  class ConfigIoSelector (line 14) | @RequiredArgsConstructor
    method readFrom (line 21) | @Override
    method writeTo (line 26) | @Override
    method select (line 31) | private ConfigIo select(File file) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/yaml/YamlConfigIo.java
  class YamlConfigIo (line 11) | @RequiredArgsConstructor
    method readFrom (line 15) | @Override
    method writeTo (line 20) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/yaml/YamlReader.java
  class YamlReader (line 31) | class YamlReader extends AbstractConfigReader {
    method YamlReader (line 32) | YamlReader(File file, FsReader fileFsReader) {
    method properties (line 36) | @Override
    method multiLineKey (line 61) | private String multiLineKey(String line, int currentOffset) {
    method isListValue (line 72) | private boolean isListValue(String line) {
    method listValue (line 77) | private int listValue(List<Property> result,
    method listValueEnd (line 97) | private boolean listValueEnd(String nextLine, int currentOffset) {
    method multiLineValue (line 105) | private int multiLineValue(List<Property> result, String key, Deque<Ke...
    method isComplexValue (line 132) | private boolean isComplexValue(String line, int currentOffset) {
    method addComplexValue (line 138) | private int addComplexValue(List<Property> result,
    method complexValueEnd (line 163) | private boolean complexValueEnd(String nextLine, int currentOffset) {
    method parseSimpleProperty (line 171) | private void parseSimpleProperty(List<Property> result,
    method separatorIndex (line 199) | private int separatorIndex(String line, int offset) {
    method valueEmpty (line 203) | private boolean valueEmpty(String line, int separatorIndex) {
    method removePropertiesWithBiggerOffset (line 207) | private void removePropertiesWithBiggerOffset(Deque<KeyOffset> current...
    method skip (line 213) | private boolean skip(String line) {
    method offsetIndex (line 218) | private int offsetIndex(String line) {
    method itsLastProperty (line 225) | private boolean itsLastProperty(int i, int currentOffset) {
    method addValue (line 243) | private void addValue(List<Property> result,
    method mergeKey (line 257) | private String mergeKey(Deque<KeyOffset> currentProperty, String key) {
    method toKey (line 264) | private String toKey(Deque<KeyOffset> currentProperty) {
    class KeyOffset (line 270) | @RequiredArgsConstructor
      method toString (line 276) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/yaml/YamlTree.java
  type YamlTree (line 5) | public interface YamlTree {
    method toYaml (line 6) | String toYaml(Map<String, String> flatProperties);

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/yaml/YamlTreeImpl.java
  class YamlTreeImpl (line 16) | public class YamlTreeImpl implements YamlTree {
    method YamlTreeImpl (line 20) | public YamlTreeImpl() {
    method YamlTreeImpl (line 24) | public YamlTreeImpl(boolean addEmptyLineAfterSections) {
    method toYaml (line 28) | @Override
    class TreeCreator (line 34) | static class TreeCreator {
      method toTree (line 35) | Map<String, Object> toTree(Map<String, String> flatProperties) {
      method propertyToTree (line 45) | @SuppressWarnings("unchecked")
      method offsetForMultilineValue (line 65) | private String offsetForMultilineValue(int parts, String value) {
      method withOffsets (line 77) | private String withOffsets(int parts, String value) {
      method splitKey (line 83) | private List<String> splitKey(String key) {
    class YamlDumper (line 109) | class YamlDumper {
      method toYamlFromTree (line 112) | String toYamlFromTree(Map<String, Object> tree) {
      method dump (line 119) | private void dump(Map<String, Object> tree, int indent, boolean empt...
      method dumpValue (line 130) | @SuppressWarnings("unchecked")
      method sort (line 142) | private List<Entry<String, Object>> sort(Map<String, Object> origina...
      method byDepth (line 150) | private int byDepth(Entry<String, Object> entry) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/io/yaml/YamlWriter.java
  class YamlWriter (line 15) | @RequiredArgsConstructor
    method YamlWriter (line 20) | public YamlWriter(File file) {
    method write (line 24) | @Override
    method write (line 29) | @Override
    method serialize (line 34) | @Override
    method serializeMap (line 43) | private String serializeMap(Map<String, String> properties) {
    method doWrite (line 47) | private void doWrite(String yaml, OpenOption... openOptions) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/repository/ComponentGraph.java
  type ComponentGraph (line 9) | public interface ComponentGraph {
    method getConfigFilesOf (line 11) | List<ConfigFile> getConfigFilesOf(String component, String environment...
    method getFolderOf (line 13) | Optional<File> getFolderOf(String component);

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/repository/ComponentGraphImpl.java
  class ComponentGraphImpl (line 27) | @RequiredArgsConstructor(access = PRIVATE)
    method traverseFrom (line 33) | public static ComponentGraph traverseFrom(File rootDir) {
    method collectFoldersByComponentType (line 44) | private static Map<String, List<File>> collectFoldersByComponentType(S...
    method getConfigFilesOf (line 51) | @Override //todo includes from diff components shouldn't be parsed mul...
    method configWith (line 68) | private Predicate<File> configWith(ConfigType configType) {
    method forEnv (line 72) | private Predicate<File> forEnv(String environment) {
    method configPriority (line 76) | private Comparator<File> configPriority() {
    method amountOfEnvironments (line 81) | private long amountOfEnvironments(File f) {
    method getFolderOf (line 87) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/repository/ComponentNotFoundException.java
  class ComponentNotFoundException (line 11) | @RequiredArgsConstructor
    method withParentComponent (line 16) | public ComponentNotFoundException withParentComponent(String parent) {
    method getMessage (line 21) | @Override
    method chainMessage (line 27) | private String chainMessage() {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/repository/CompositePropertiesRepository.java
  class CompositePropertiesRepository (line 16) | @RequiredArgsConstructor
    method compositeOf (line 20) | public static PropertiesRepository compositeOf(List<PropertiesReposito...
    method getPropertiesOf (line 25) | @Override
    method mergeSecondToFirst (line 32) | private Map<String, Property> mergeSecondToFirst(Map<String, Property>...

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/repository/ConfigFile.java
  class ConfigFile (line 29) | @Getter
    method parseUsing (line 38) | public RawConfig parseUsing(ConfigIo configIo) {
    method parseTempProperties (line 50) | private List<Property> parseTempProperties(Map<Integer, String> commen...
    method parseIncludes (line 58) | private List<Include> parseIncludes(Collection<String> comments) {
    method containsIgnoreDirective (line 66) | private boolean containsIgnoreDirective(Collection<String> comments) {
    method toString (line 70) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/repository/EnvProfilesComponentGraph.java
  class EnvProfilesComponentGraph (line 18) | @RequiredArgsConstructor
    method getConfigFilesOf (line 23) | @Override
    method getConfigFilesWithProfilesOf (line 30) | private List<ConfigFile> getConfigFilesWithProfilesOf(String environme...
    method joinConfigs (line 35) | private List<ConfigFile> joinConfigs(List<ConfigFile> standard, List<C...
    method doesNotContain (line 46) | private Predicate<ConfigFile> doesNotContain(String environment) {
    method getFolderOf (line 51) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/repository/FilePropertiesRepository.java
  class FilePropertiesRepository (line 19) | @RequiredArgsConstructor
    method getPropertiesOf (line 26) | @Override
    class OriginalComponent (line 31) | @RequiredArgsConstructor
      method getProperties (line 41) | public Map<String, Property> getProperties() {
      method configFiles (line 45) | private List<ConfigFile> configFiles() {
      method readAndParse (line 49) | private Map<String, Property> readAndParse(List<ConfigFile> componen...
      method parse (line 58) | private Map<String, Property> parse(ConfigFile configFile) {
      method includeResolver (line 64) | private Map<String, Property> includeResolver(Include include) {
      method componentFrom (line 72) | private OriginalComponent componentFrom(Include include) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/repository/Include.java
  class Include (line 12) | @Getter
    method parse (line 21) | public static Include parse(String definition, String defaultEnv) {
    method toString (line 32) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/repository/Includes.java
  class Includes (line 11) | @RequiredArgsConstructor(access = PRIVATE)
    method isInclude (line 18) | public static boolean isInclude(String line) {
    method from (line 23) | public static Includes from(String line) {
    method withDefaultEnv (line 27) | public List<Include> withDefaultEnv(String defaultEnv) {
    method parseIncludes (line 35) | private List<Include> parseIncludes(String defaultEnv) {
    method componentStartIndex (line 43) | private int componentStartIndex() {
    method tryPrefix (line 54) | private int tryPrefix(String value, String prefix) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/repository/RawConfig.java
  class RawConfig (line 17) | @RequiredArgsConstructor
    method getBaseAndIncludedProperties (line 22) | public Map<String, Property> getBaseAndIncludedProperties(Function<Inc...
    method filterProperties (line 32) | private Map<String, Property> filterProperties(List<String> profiles, ...
    method byMultilineVars (line 43) | private Predicate<OverrideProperty> byMultilineVars() {
    method byPropertiesForProfile (line 47) | private Predicate<OverrideProperty> byPropertiesForProfile(List<String...
    method byPropertiesForEnv (line 51) | private Predicate<OverrideProperty> byPropertiesForEnv(String env) {
    method override (line 55) | private void override(Map<String, Property> propsByKey, Predicate<Over...
    method isOverrideProperty (line 64) | private boolean isOverrideProperty(Property p) {
    method getIncludedPropertiesUsing (line 68) | private Map<String, Property> getIncludedPropertiesUsing(Function<Incl...

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/ChainedResolver.java
  class ChainedResolver (line 13) | @RequiredArgsConstructor(access = PRIVATE)
    method chainOf (line 17) | public static Resolver chainOf(RecursiveResolver... resolvers) {
    method findStatementIn (line 21) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/RecursiveResolver.java
  type RecursiveResolver (line 8) | public interface RecursiveResolver extends Resolver {
    method resolve (line 9) | @Override
    method findStatementIn (line 23) | Optional<Statement> findStatementIn(CharSequence line);
    type Statement (line 25) | interface Statement {
      method getStartIndex (line 26) | int getStartIndex();
      method getEndIndex (line 28) | int getEndIndex();
      method resolveFor (line 30) | String resolveFor(DeclaringComponent sourceOfValue, DeclaringCompone...

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/expression/ExpressionEvaluator.java
  class ExpressionEvaluator (line 12) | @RequiredArgsConstructor
    method withFunctionsFrom (line 17) | public static ExpressionEvaluator withFunctionsFrom(Class<?>... functi...
    method evaluate (line 28) | public String evaluate(String value) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/expression/ExpressionResolver.java
  class ExpressionResolver (line 20) | @RequiredArgsConstructor
    method findStatementIn (line 25) | @Override
    method toExpression (line 31) | private Expression toExpression(Matcher matcher) {
    class Expression (line 35) | @RequiredArgsConstructor
      method resolveFor (line 43) | @Override
      method toString (line 52) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/expression/functions/CustomIoApi.java
  class CustomIoApi (line 8) | public class CustomIoApi {
    method readBytes (line 9) | public static byte[] readBytes(String path) {
    method readBytesOrEmpty (line 13) | public static byte[] readBytesOrEmpty(String path) {
    method readString (line 18) | public static String readString(String path) {
    method readStringOrEmpty (line 22) | public static String readStringOrEmpty(String path) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/expression/functions/CustomStringApi.java
  class CustomStringApi (line 9) | public class CustomStringApi {
    method findGroup (line 10) | public static String findGroup(String regex, String line) {
    method findGroupOrDefault (line 14) | public static String findGroupOrDefault(String regex, String line, Str...
    method base64 (line 19) | public static String base64(String line) {
    method bytesBase64 (line 23) | public static String bytesBase64(byte[] bytes) {
    method delete (line 27) | public static String delete(String line, String toDelete) {
    method substringAfterFirst (line 31) | public static String substringAfterFirst(String line, String substring) {
    method removeLineSeparators (line 36) | public static String removeLineSeparators(String line) {
    method replaceLineSeparators (line 40) | public static String replaceLineSeparators(String line, String replace...
    method substringAfterLast (line 44) | public static String substringAfterLast(String line, String substring) {
    method substringAfter (line 49) | private static String substringAfter(String line, int i, String substr...

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/Placeholder.java
  class Placeholder (line 14) | @Getter
    method resolveUsing (line 28) | public Property resolveUsing(PlaceholderResolveStrategy strategy, Decl...
    method getReferencedComponent (line 33) | public DeclaringComponent getReferencedComponent() {
    method isSelfReferenced (line 37) | public boolean isSelfReferenced() {
    method referencedTo (line 41) | public boolean referencedTo(DeclaringComponent c) {
    method overrideBy (line 45) | public Placeholder overrideBy(DeclaringComponent c) {
    method toString (line 50) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/PlaceholderBorders.java
  class PlaceholderBorders (line 16) | @With(PRIVATE)
    method PlaceholderBorders (line 30) | private PlaceholderBorders(StringBuilder line) {
    method findPlaceholderIn (line 34) | public static Optional<PlaceholderBorders> findPlaceholderIn(CharSeque...
    method findPlaceholderIn (line 38) | public static Optional<PlaceholderBorders> findPlaceholderIn(CharSeque...
    method searchOpenSign (line 44) | private Optional<PlaceholderBorders> searchOpenSign() {
    method parseComponentName (line 55) | private Optional<PlaceholderBorders> parseComponentName() {
    method parseEnvName (line 77) | private Optional<PlaceholderBorders> parseEnvName() {
    method parseKey (line 91) | private Optional<PlaceholderBorders> parseKey() {
    method parseDefaultValue (line 110) | private Optional<PlaceholderBorders> parseDefaultValue() {
    method notAllowedSymbol (line 133) | private boolean notAllowedSymbol(char c) {
    method getConfigType (line 137) | private String getConfigType(String contextConfigType) {
    method getComponent (line 141) | private String getComponent() {
    method getEnvironment (line 145) | private String getEnvironment(String contextEnv) {
    method getKey (line 149) | private String getKey() {
    method getDefaultValue (line 153) | private String getDefaultValue() {
    method toPlaceholder (line 157) | public Placeholder toPlaceholder(String contextConfigType, String cont...
    method toString (line 167) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/PlaceholderResolver.java
  class PlaceholderResolver (line 23) | @RequiredArgsConstructor(access = PRIVATE)
    method PlaceholderResolver (line 31) | public PlaceholderResolver(EnvironmentRepository environmentRepository,
    method findStatementIn (line 37) | @Override
    class PlaceholderStatement (line 42) | @RequiredArgsConstructor
      method getStartIndex (line 46) | @Override
      method getEndIndex (line 51) | @Override
      method resolveFor (line 56) | @Override
      method canBeOverridden (line 74) | private boolean canBeOverridden(Placeholder p, DeclaringComponent so...
      method overrideByParents (line 79) | private String overrideByParents(Placeholder p, DeclaringComponent s...
      method resolve (line 100) | private String resolve(Placeholder p, DeclaringComponent root) {
      method hasProfileOfRootEnv (line 106) | private boolean hasProfileOfRootEnv(Placeholder p, DeclaringComponen...
      method currentResolverWithVisited (line 115) | private PlaceholderResolver currentResolverWithVisited(Placeholder p...
      method toString (line 126) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/component/ComponentProperty.java
  type ComponentProperty (line 5) | public interface ComponentProperty {
    method key (line 6) | String key();
    method resolveFor (line 8) | Optional<String> resolveFor(String component, String environment);

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/component/ComponentResolveStrategy.java
  class ComponentResolveStrategy (line 15) | @RequiredArgsConstructor
    method resolve (line 19) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/component/properties/ComponentProperties.java
  class ComponentProperties (line 15) | @RequiredArgsConstructor
    method get (line 22) | public Map<String, ComponentProperty> get() {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/component/properties/ConfigDirProperty.java
  class ConfigDirProperty (line 12) | @RequiredArgsConstructor
    method key (line 17) | @Override
    method resolveFor (line 22) | @Override
    method findDirBy (line 30) | private Optional<String> findDirBy(String component) {
    method originalNameOf (line 36) | private String originalNameOf(String component, String env) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/component/properties/ConfigRootDirProperty.java
  class ConfigRootDirProperty (line 11) | public class ConfigRootDirProperty implements ComponentProperty {
    method ConfigRootDirProperty (line 14) | public ConfigRootDirProperty(File configRoot) {
    method key (line 18) | @Override
    method resolveFor (line 23) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/component/properties/NameProperty.java
  class NameProperty (line 9) | public class NameProperty implements ComponentProperty {
    method key (line 10) | @Override
    method resolveFor (line 15) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/component/properties/ResultDirProperty.java
  class ResultDirProperty (line 12) | @RequiredArgsConstructor
    method key (line 16) | @Override
    method resolveFor (line 21) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/composite/CompositeResolveStrategy.java
  class CompositeResolveStrategy (line 12) | @RequiredArgsConstructor
    method composite (line 16) | public static PlaceholderResolveStrategy composite(List<PlaceholderRes...
    method resolve (line 20) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/environment/EnvProperty.java
  type EnvProperty (line 7) | public interface EnvProperty {
    method key (line 8) | String key();
    method resolveFor (line 10) | Optional<String> resolveFor(String component, Environment environment);

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/environment/EnvironmentResolveStrategy.java
  class EnvironmentResolveStrategy (line 18) | @RequiredArgsConstructor
    method resolve (line 23) | @Override
    method getEnvironment (line 35) | private Environment getEnvironment(String environment) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/environment/properties/ComponentOrderProperty.java
  class ComponentOrderProperty (line 15) | public class ComponentOrderProperty implements EnvProperty {
    method key (line 16) | @Override
    method resolveFor (line 21) | @Override
    method findIndexOf (line 29) | private Function<List<Component>, Optional<String>> findIndexOf(String...

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/environment/properties/EnvNameProperty.java
  class EnvNameProperty (line 10) | public class EnvNameProperty implements EnvProperty {
    method key (line 11) | @Override
    method resolveFor (line 16) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/environment/properties/EnvironmentProperties.java
  class EnvironmentProperties (line 11) | public class EnvironmentProperties {
    method get (line 12) | public Map<String, EnvProperty> get() {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/environment/properties/GroupNameProperty.java
  class GroupNameProperty (line 9) | public class GroupNameProperty implements EnvProperty {
    method key (line 10) | @Override
    method resolveFor (line 15) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/environment/properties/IpProperty.java
  class IpProperty (line 9) | public class IpProperty implements EnvProperty {
    method key (line 10) | @Override
    method resolveFor (line 15) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/environment/properties/PortOffsetProperty.java
  class PortOffsetProperty (line 10) | public class PortOffsetProperty implements EnvProperty {
    method key (line 11) | @Override
    method resolveFor (line 16) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/standard/StandardResolveStrategy.java
  class StandardResolveStrategy (line 12) | @RequiredArgsConstructor
    method resolve (line 16) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/system/SystemResolveStrategy.java
  class SystemResolveStrategy (line 19) | @RequiredArgsConstructor
    method systemPropertiesResolveStrategy (line 27) | public static PlaceholderResolveStrategy systemPropertiesResolveStrate...
    method envVariablesResolveStrategy (line 31) | public static PlaceholderResolveStrategy envVariablesResolveStrategy() {
    method resolve (line 35) | @Override
    method escapeOnWindows (line 44) | private String escapeOnWindows(String value, String key) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/serializers/ConfigDiff.java
  class ConfigDiff (line 17) | public class ConfigDiff {
    method storeDiffFor (line 20) | public void storeDiffFor(File previousConfigFile, Collection<Property>...
    method diffFileFor (line 33) | private File diffFileFor(File current) {
    method readOldConfig (line 37) | private Map<String, String> readOldConfig(File current) {
    method compare (line 46) | private Map<String, String> compare(Map<String, String> old, Collectio...
    method linesEquals (line 65) | private boolean linesEquals(String current, String old) {
    method markAdded (line 70) | private void markAdded(String key, String value, Map<String, String> r...
    method markRemoved (line 74) | private void markRemoved(String key, String value, Map<String, String>...
    method markChanged (line 78) | private void markChanged(String key, String oldValue, String currentVa...

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/serializers/ConfigResult.java
  class ConfigResult (line 18) | @Data
    method toJson (line 26) | public static String toJson(List<ConfigResult> configResults) {
    method groupsByService (line 30) | public static List<ServiceConfigs> groupsByService(List<ConfigResult> ...
    class ServiceConfigs (line 39) | @Getter
      method ServiceConfigs (line 44) | ServiceConfigs(String service, List<ConfigResult> configResults) {
    class FileResult (line 51) | @Getter
      method FileResult (line 58) | FileResult(ConfigResult configResult) {
      method FileResult (line 62) | public FileResult(Template template) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/serializers/PropertySerializers.java
  class PropertySerializers (line 24) | @RequiredArgsConstructor(access = PRIVATE)
    method withConfigDiff (line 26) | public static BiConsumer<File, Collection<Property>> withConfigDiff() {
    method asConfigResult (line 31) | public static PropertySerializer<ConfigResult> asConfigResult() {
    method toFileIn (line 39) | public static PropertySerializer<File> toFileIn(File dir, BiConsumer<F...
    method copyTemplate (line 59) | private static void copyTemplate(Template template, String componentNa...
    method asString (line 67) | public static PropertySerializer<String> asString() {
    method extensionByConfigFormat (line 73) | private static ConfigFormat extensionByConfigFormat(Collection<Propert...
    method withLegacySupport (line 78) | public static PropertySerializer<File> withLegacySupport(PropertySeria...

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/templates/BinaryTemplate.java
  class BinaryTemplate (line 11) | @Getter
    method BinaryTemplate (line 19) | public BinaryTemplate(String templateName, File source, File destinati...
    method getFileName (line 26) | @Override
    method getContent (line 31) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/templates/MustacheTemplateProcessor.java
  class MustacheTemplateProcessor (line 15) | public class MustacheTemplateProcessor implements TemplateContentPostPro...
    method process (line 18) | @Override
    method isMustacheTemplate (line 28) | private boolean isMustacheTemplate(File source, String templateType) {
    method compile (line 32) | private Template compile(File currentTemplate, String source) {
    method templateLoader (line 38) | private Mustache.TemplateLoader templateLoader(File currentTemplate) {
    method toYaml (line 46) | private Map<String, Object> toYaml(TypedProperties properties) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/templates/StringTemplate.java
  class StringTemplate (line 20) | @RequiredArgsConstructor
    method StringTemplate (line 32) | StringTemplate(String templateName, File source, File destination, Pat...
    method isValidPlaceholder (line 40) | public static boolean isValidPlaceholder(String value) {
    method resolveBy (line 44) | StringTemplate resolveBy(Resolver resolver, DeclaringComponent current...
    method templateNameWithoutBrackets (line 58) | String templateNameWithoutBrackets() {
    method postProcessContent (line 62) | StringTemplate postProcessContent(TemplateContentPostProcessor postPro...
    method doResolve (line 69) | private void doResolve(Matcher m, StringBuffer result, Resolver resolv...
    method resolve (line 82) | private String resolve(String placeholder, DeclaringComponent currentC...
    method doResolve (line 96) | private String doResolve(String placeholder, Resolver resolver, Declar...
    method addOffsetForMultiLineValue (line 100) | private String addOffsetForMultiLineValue(String value, Matcher m) {
    method getFileName (line 106) | @Override
    method getContentAsBytes (line 111) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/templates/TemplateContentPostProcessor.java
  type TemplateContentPostProcessor (line 7) | public interface TemplateContentPostProcessor {
    method process (line 8) | String process(String templateType,

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/templates/TemplateDefinition.java
  class TemplateDefinition (line 14) | @RequiredArgsConstructor
    method TemplateDefinition (line 27) | public TemplateDefinition(String templateType, String templateName, Te...
    method resolve (line 31) | public Template resolve(Resolver resolver, TypedProperties properties) {
    method toStringTemplate (line 36) | private StringTemplate toStringTemplate(Resolver resolver,
    method toBinaryTemplate (line 53) | private Template toBinaryTemplate(Resolver resolver, TypedProperties p...
    method isBinaryTemplate (line 59) | private boolean isBinaryTemplate() {
    method toStringTemplate (line 63) | private StringTemplate toStringTemplate(File destination) {
    method isCorrect (line 70) | private boolean isCorrect() {
    method getTemplateFile (line 74) | private File getTemplateFile() {
    method destinationFileFor (line 85) | private File destinationFileFor(DeclaringComponent currentComponent, R...
    method destinationDir (line 89) | private String destinationDir(DeclaringComponent currentComponent, Res...
    method setFromFile (line 93) | public void setFromFile(String fromFile) {
    method setToFile (line 100) | public void setToFile(String toFile) {
    method toString (line 104) | @Override

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/templates/TemplateDefinitionParser.java
  type TemplateDefinitionParser (line 7) | public interface TemplateDefinitionParser {
    method parse (line 8) | Collection<TemplateDefinition> parse(Collection<Property> componentPro...

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/templates/TemplatePattern.java
  class TemplatePattern (line 13) | @With
    method defaultPattern (line 26) | public static TemplatePattern defaultPattern() {
    method startsWithTemplatePrefix (line 39) | public boolean startsWithTemplatePrefix(String key) {
    method extractTemplateType (line 43) | public String extractTemplateType(String str) {
    method extractTemplateName (line 49) | public String extractTemplateName(String str) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/templates/TemplatesService.java
  class TemplatesService (line 20) | @RequiredArgsConstructor
    method TemplatesService (line 25) | public TemplatesService() {
    method resolveTemplatesBy (line 33) | public static UnaryOperator<TypedProperties> resolveTemplatesBy(Resolv...
    method resolveTemplates (line 40) | public List<Template> resolveTemplates(TypedProperties properties, Res...
    method findTemplateDefinitionsFrom (line 47) | private Collection<TemplateDefinition> findTemplateDefinitionsFrom(Col...

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/templates/definition/parser/ArrowNotationParser.java
  class ArrowNotationParser (line 21) | @RequiredArgsConstructor
    method parse (line 25) | @Override
    method processProperty (line 33) | private List<TemplateDefinition> processProperty(Property property) {
    method processWithAsterisk (line 45) | private List<TemplateDefinition> processWithAsterisk(String key, Strin...
    method createTemplate (line 56) | private TemplateDefinition createTemplate(String key, String from, Str...
    method correctNotation (line 66) | private boolean correctNotation(String key) {

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/templates/definition/parser/FromToNotationParser.java
  class FromToNotationParser (line 13) | @RequiredArgsConstructor
    method parse (line 17) | @Override
    method getOrCreate (line 32) | private TemplateDefinition getOrCreate(String key, Map<String, Templat...

FILE: microconfig-core/src/main/java/io/microconfig/core/properties/templates/definition/parser/SquareBracketsNotationParser.java
  class SquareBracketsNotationParser (line 19) | @RequiredArgsConstructor
    method parse (line 23) | @Override
    method processProperty (line 31) | private List<TemplateDefinition> processProperty(Property property) {
    method correctNotation (line 46) | private boolean correctNotation(Property property) {
    method createTemplateDefinition (line 52) | private TemplateDefinition createTemplateDefinition(String templateTyp...

FILE: microconfig-core/src/test/java/io/microconfig/core/ClasspathReader.java
  class ClasspathReader (line 10) | public class ClasspathReader {
    method classpathFile (line 11) | public static File classpathFile(String name) {
    method read (line 19) | public static String read(String file) {

FILE: microconfig-core/src/test/java/io/microconfig/core/MicroconfigRunnerTest.java
  class MicroconfigRunnerTest (line 16) | class MicroconfigRunnerTest {
    method testBuild (line 20) | @Test
    method testBuildAbstract (line 30) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/MicroconfigTest.java
  class MicroconfigTest (line 27) | public class MicroconfigTest {
    method findTests (line 31) | @TestFactory
    method testIncorrectRootDir (line 41) | @Test
    method isExpectation (line 46) | private boolean isExpectation(File file) {
    method overriddenTest (line 52) | private boolean overriddenTest(File file) {
    method toTest (line 57) | private DynamicTest toTest(File expectation) {
    method toTest (line 63) | private DynamicTest toTest(File expectation, String component, String ...
    method getComponentName (line 76) | private String getComponentName(File expectation) {
    method getEnvName (line 81) | private String getEnvName(File expectation) {
    method build (line 85) | private String build(String component, String env) {
    method readExpectation (line 98) | private String readExpectation(File expectation) {
    method toPath (line 108) | private String toPath(File file) {

FILE: microconfig-core/src/test/java/io/microconfig/core/TemplatesTest.java
  class TemplatesTest (line 17) | public class TemplatesTest {
    method testMustache (line 21) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/configtypes/CompositeConfigTypeRepositoryTest.java
  class CompositeConfigTypeRepositoryTest (line 15) | class CompositeConfigTypeRepositoryTest {
    method returnsFirstNotEmptyTypes (line 20) | @Test
    method testExceptionIfNoTypesConfigured (line 32) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/configtypes/ConfigTypeImplTest.java
  class ConfigTypeImplTest (line 14) | class ConfigTypeImplTest {
    method createByNameAndExtension (line 15) | @Test
    method createByName (line 23) | @Test
    method extensionsShouldStartWithDot (line 31) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/configtypes/CustomConfigTypeRepositoryTest.java
  class CustomConfigTypeRepositoryTest (line 12) | class CustomConfigTypeRepositoryTest {
    method loadCustomFilesFromFile (line 13) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/configtypes/StandardConfigTypeRepositoryTest.java
  class StandardConfigTypeRepositoryTest (line 8) | class StandardConfigTypeRepositoryTest {
    method standardTypesRepo (line 9) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/configtypes/StandardConfigTypeTest.java
  class StandardConfigTypeTest (line 9) | class StandardConfigTypeTest {
    method shouldImplementConfigType (line 10) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/environments/ComponentFactoryImplTest.java
  class ComponentFactoryImplTest (line 10) | class ComponentFactoryImplTest {
    method createComponent (line 16) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/environments/ComponentGroupImplTest.java
  class ComponentGroupImplTest (line 12) | class ComponentGroupImplTest {
    method ipOptionalWrapping (line 17) | @Test
    method findComponentByName (line 27) | @Test
    method string (line 38) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/environments/ComponentImplTest.java
  class ComponentImplTest (line 17) | class ComponentImplTest {
    method filterProperties (line 24) | @Test
    method string (line 34) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/environments/ComponentsImplTest.java
  class ComponentsImplTest (line 16) | class ComponentsImplTest {
    method filterPropertiesForContainedComponents (line 28) | @Test
    method string (line 41) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/environments/EnvironmentImplTest.java
  class EnvironmentImplTest (line 20) | class EnvironmentImplTest {
    method setUp (line 35) | @BeforeEach
    method filterGroupsByIp (line 48) | @Test
    method findGroupByName (line 57) | @Test
    method findGroupWithComponentName (line 63) | @Test
    method getAllComponents (line 71) | @Test
    method getComponentWithName (line 76) | @Test
    method getOrCreateComponentWithName (line 84) | @Test
    method findComponentsFrom (line 94) | @Test
    method testToString (line 107) | @Test
    method components (line 114) | private Components components(Component... components) {

FILE: microconfig-core/src/test/java/io/microconfig/core/environments/repository/ComponentDefinitionTest.java
  class ComponentDefinitionTest (line 14) | class ComponentDefinitionTest {
    method factoryMethods (line 18) | @Test
    method toComponent (line 24) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/environments/repository/FileEnvironmentRepositoryTest.java
  class FileEnvironmentRepositoryTest (line 25) | class FileEnvironmentRepositoryTest {
    method noEnvDirException (line 33) | @Test
    method envExceptionWrappingOnFileRead (line 39) | @Test
    method envExceptionWrappingOnGroupParse (line 47) | @Test
    method sameEnvNamesException (line 54) | @Test
    method parseEnvFiles (line 64) | @Test
    method filterMethods (line 76) | @Test
    method testDev (line 92) | private void testDev(Environment env) {
    method testTest (line 119) | private void testTest(Environment env) {
    method testStaging (line 147) | private void testStaging(Environment env) {
    method testProd (line 179) | private void testProd(Environment env) {
    method testAlias (line 206) | private void testAlias(Environment env) {
    method testGroup (line 216) | private void testGroup(Environment environment, String groupName, Stri...
    method testComponents (line 222) | private void testComponents(String env, List<String> expected, List<Co...
    method filter (line 227) | private Environment filter(List<Environment> envs, String name) {

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/ComponentWithEnvTest.java
  class ComponentWithEnvTest (line 7) | class ComponentWithEnvTest {
    method testToString (line 8) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/FileBasedComponentTest.java
  class FileBasedComponentTest (line 11) | class FileBasedComponentTest {
    method getters (line 15) | @Test
    method factoryMethod (line 22) | @Test
    method parentComponent (line 27) | @Test
    method string (line 32) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/PropertiesImplTest.java
  class PropertiesImplTest (line 18) | class PropertiesImplTest {
    method compositeFactoryMethod (line 23) | @Test
    method resolveBy (line 37) | @Test
    method withoutTempValues (line 51) | @Test
    method getProperties (line 64) | @Test
    method getPropertyWithKey (line 86) | @Test
    method save (line 94) | @Test
    method asTypedProperties (line 106) | @Test
    method getProperty (line 112) | private Property getProperty(int order) {

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/PropertyImplTest.java
  class PropertyImplTest (line 14) | class PropertyImplTest {
    method parseYaml (line 23) | @Test
    method parseProp (line 36) | @Test
    method failOnMissingSeparator (line 49) | @Test
    method factoryMethods (line 54) | @Test
    method helperMethods (line 59) | @Test
    method string (line 71) | @Test
    method resolve (line 77) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/ResolveExceptionTest.java
  class ResolveExceptionTest (line 9) | class ResolveExceptionTest {
    method withoutCause (line 14) | @Test
    method withCauseMessage (line 30) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/TypedPropertiesImplTest.java
  class TypedPropertiesImplTest (line 22) | class TypedPropertiesImplTest {
    method setup (line 28) | @BeforeEach
    method getDeclaringComponent (line 34) | @Test
    method resolve (line 42) | @Test
    method withoutTempValues (line 58) | @Test
    method propertiesAsMap (line 63) | @Test
    method propertiesAsKeyValue (line 71) | @Test
    method properties (line 79) | @Test
    method propertyWithKey (line 84) | @Test
    method getMultipleProperties (line 90) | @Test
    method serialize (line 102) | @Test
    method testToString (line 108) | @Test
    method withProperties (line 116) | private TypedProperties withProperties(Collection<Property> properties) {
    method property (line 123) | private Property property(String key) {

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/io/properties/PropertiesConfigIoTest.java
  class PropertiesConfigIoTest (line 14) | class PropertiesConfigIoTest {
    method test (line 17) | @Test
    method expectedMap (line 23) | private Map<String, String> expectedMap() {

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/io/yaml/YamlConfigIoTest.java
  class YamlConfigIoTest (line 18) | class YamlConfigIoTest {
    method testSimpleYaml (line 21) | @Test
    method testInnerYaml (line 40) | @Test
    method testInnerYaml2 (line 59) | @Test
    method testMultiline (line 73) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/io/yaml/YamlTreeImplTest.java
  class YamlTreeImplTest (line 15) | class YamlTreeImplTest {
    method testEscaped (line 16) | @Test
    method testDoubleEscaped (line 30) | @Test
    method testSortOrder (line 42) | @Test
    method testList (line 50) | @Test
    method testWriteInner (line 58) | @Test
    method toYaml (line 76) | private String toYaml(String file) {
    method doCompare (line 82) | private void doCompare(String expected, Map<String, String> initial) {
    method assertStringEquals (line 86) | private void assertStringEquals(String expected, String actual) {

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/repository/ComponentNotFoundExceptionTest.java
  class ComponentNotFoundExceptionTest (line 7) | class ComponentNotFoundExceptionTest {
    method test (line 8) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/repository/CompositePropertiesRepositoryTest.java
  class CompositePropertiesRepositoryTest (line 26) | class CompositePropertiesRepositoryTest {
    method should_merge_in_order (line 35) | @Test
    method should_return_empty_map_if_unresolved (line 45) | @Test
    method should_return_same_repository_if_only_one_supplied (line 54) | @Test
    method propsMap (line 61) | private Map<String, Property> propsMap(Property... props) {
    method second (line 65) | private Map<String, Property> second() {

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/repository/EnvProfilesComponentGraphTest.java
  class EnvProfilesComponentGraphTest (line 21) | class EnvProfilesComponentGraphTest {
    method setUp (line 28) | @BeforeEach
    method test (line 36) | @Test
    method test2 (line 43) | @Test
    method test3 (line 50) | @Test
    method test4 (line 57) | @Test
    method test5 (line 64) | @Test
    method test6 (line 76) | @Test
    method mockGraph (line 88) | private void mockGraph(String env, String... files) {
    method assertResult (line 93) | private void assertResult(String... names) {
    method files (line 100) | private List<ConfigFile> files(String... names) {

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/repository/IncludeTest.java
  class IncludeTest (line 9) | class IncludeTest {
    method testParse (line 10) | @Test
    method testInclude (line 18) | private void testInclude(String expectedComp,
    method testToString (line 25) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/resolvers/expression/ExpressionResolverTest.java
  class ExpressionResolverTest (line 8) | class ExpressionResolverTest {
    method stringApi (line 11) | @Test
    method conditionals (line 16) | @Test
    method predefinedFunctions (line 22) | @Test
    method api (line 27) | @Test
    method resolve (line 37) | private String resolve(String value) {

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/resolvers/expression/functions/CustomStringApiTest.java
  class CustomStringApiTest (line 11) | class CustomStringApiTest {
    method testFindGroup (line 12) | @Test
    method testBase64 (line 20) | @Test
    method testDelete (line 26) | @Test
    method substring (line 31) | @Test
    method testRead (line 37) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/resolvers/placeholder/PlaceholderBordersTest.java
  class PlaceholderBordersTest (line 7) | class PlaceholderBordersTest {
    method test (line 8) | @Test
    method doTest (line 22) | private void doTest(String line, String expected) {

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/templates/StringTemplatePatternTest.java
  class StringTemplatePatternTest (line 9) | class StringTemplatePatternTest {
    method startsWithTemplatePrefix (line 15) | @Test
    method extractTemplateName (line 22) | @Test

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/templates/StringTemplateTest.java
  class StringTemplateTest (line 21) | class StringTemplateTest {
    method resolveIp (line 27) | @ParameterizedTest
    method resolveDefaultValue (line 33) | @ParameterizedTest
    method testEscaped (line 39) | @Test
    method testExtendedPattern (line 44) | @Test
    method templateNameWithoutBrackets (line 49) | @Test
    method testEnvProperties (line 55) | @Test
    method testSystemProperties (line 64) | @Test
    method testMultiLinePlaceholderInTemplate (line 69) | @Test
    method resolver (line 89) | private Resolver resolver() {
    method resolve (line 93) | private void resolve(String placeholder, String expected) {

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/templates/definition/parser/ArrowNotationParserTest.java
  class ArrowNotationParserTest (line 23) | class ArrowNotationParserTest {
    method singleFile (line 27) | @Test
    method multipleFiles (line 33) | @Test
    method ifKeyContainsSquareBrackets_Ignore (line 44) | @Test
    method parseArrowProperty (line 50) | private List<TemplateDefinition> parseArrowProperty(String key, String...
    method assertTemplateDefinition (line 55) | private void assertTemplateDefinition(String from, String to, List<Tem...
    method createFile (line 64) | private void createFile(String s) throws IOException {

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/templates/definition/parser/FromToNotationParserTest.java
  class FromToNotationParserTest (line 20) | class FromToNotationParserTest {
    method singleFile (line 24) | @Test
    method createProperty (line 33) | private Property createProperty(String key, String file) {
    method parseProperties (line 37) | private ArrayList<TemplateDefinition> parseProperties(Property... prop...
    method assertTemplateDefinition (line 41) | private void assertTemplateDefinition(String from, String to, Template...

FILE: microconfig-core/src/test/java/io/microconfig/core/properties/templates/definition/parser/SquareBracketsNotationParserTest.java
  class SquareBracketsNotationParserTest (line 21) | class SquareBracketsNotationParserTest {
    method multipleTemplateNames (line 25) | @Test
    method ignoreIfAsteriskInFromFile (line 32) | @Test
    method parseArrowProperty (line 38) | private List<TemplateDefinition> parseArrowProperty(String key, String...
    method assertTemplateDefinition (line 43) | private void assertTemplateDefinition(String name, String from, String...

FILE: utils/src/main/java/io/microconfig/io/DumpedFsReader.java
  class DumpedFsReader (line 13) | public class DumpedFsReader implements FsReader {
    method readFully (line 14) | @Override
    method readLines (line 19) | @Override
    method firstLineOf (line 24) | @Override

FILE: utils/src/main/java/io/microconfig/io/FsReader.java
  type FsReader (line 8) | public interface FsReader {
    method readFully (line 9) | String readFully(File file);
    method readLines (line 11) | List<String> readLines(File file);
    method firstLineOf (line 13) | Optional<String> firstLineOf(File file, Predicate<String> predicate);

FILE: utils/src/main/java/io/microconfig/utils/CacheProxy.java
  class CacheProxy (line 13) | @RequiredArgsConstructor
    method cache (line 18) | @SuppressWarnings("unchecked")
    method invoke (line 27) | @Override
    method handleExceptionCause (line 39) | private void handleExceptionCause(Exception e) {
    class Key (line 52) | @Value

FILE: utils/src/main/java/io/microconfig/utils/CollectionUtils.java
  class CollectionUtils (line 11) | @RequiredArgsConstructor(access = PRIVATE)
    method singleValue (line 13) | public static <T> T singleValue(Collection<T> values) {
    method join (line 21) | public static <T> List<T> join(Collection<T> first, Collection<T> seco...
    method minus (line 28) | public static <T> List<T> minus(Collection<T> first, Collection<T> sec...
    method joinToSet (line 35) | public static <T> Set<T> joinToSet(Collection<T> first, Collection<T> ...
    method setOf (line 42) | @SafeVarargs

FILE: utils/src/main/java/io/microconfig/utils/ConsoleColor.java
  class ConsoleColor (line 8) | @RequiredArgsConstructor(access = PRIVATE)
    method green (line 15) | public static String green(String message) {
    method red (line 19) | public static String red(String message) {
    method yellow (line 23) | public static String yellow(String message) {
    method applyColor (line 27) | private static String applyColor(String message, String color) {

FILE: utils/src/main/java/io/microconfig/utils/FileUtils.java
  class FileUtils (line 20) | @RequiredArgsConstructor(access = PRIVATE)
    method copyPermissions (line 24) | public static void copyPermissions(Path from, Path to) {
    method write (line 34) | public static void write(File file, String content) {
    method write (line 38) | public static void write(Path file, String content, OpenOption... opti...
    method write (line 42) | public static void write(Path file, byte[] content, OpenOption... opti...
    method delete (line 55) | public static void delete(File... paths) {
    method delete (line 59) | public static void delete(File path) {
    method deleteDir (line 73) | private static boolean deleteDir(File dir) {
    method canonical (line 80) | public static File canonical(File repoDir) {
    method walk (line 88) | public static Stream<Path> walk(Path path) {
    method getExtension (line 96) | public static String getExtension(File file) {
    method getName (line 102) | public static String getName(File file) {
    method extensionIndex (line 107) | private static int extensionIndex(File file) {

FILE: utils/src/main/java/io/microconfig/utils/IoUtils.java
  class IoUtils (line 12) | @RequiredArgsConstructor(access = PRIVATE)
    method readFully (line 14) | public static String readFully(File file) {
    method readAllBytes (line 22) | public static byte[] readAllBytes(File file) {
    method readClasspathResource (line 30) | public static String readClasspathResource(String file) {
    method readFully (line 34) | public static String readFully(InputStream is) {
    method readAllBytes (line 38) | public static byte[] readAllBytes(InputStream is) {
    method doRead (line 42) | private static ByteArrayOutputStream doRead(InputStream is) {
    method readLines (line 58) | public static List<String> readLines(File file) {

FILE: utils/src/main/java/io/microconfig/utils/Logger.java
  class Logger (line 11) | @RequiredArgsConstructor(access = PRIVATE)
    method error (line 16) | public static void error(Throwable e) {
    method error (line 22) | public static void error(String message, Throwable e) {
    method warn (line 35) | public static void warn(String message) {
    method announce (line 39) | public static void announce(String message) {
    method info (line 43) | public static void info(String message) {
    method error (line 48) | public static void error(String message) {
    method isErrorOccurred (line 53) | public static boolean isErrorOccurred() {
    method enableLogger (line 57) | public static void enableLogger(boolean enabled) {

FILE: utils/src/main/java/io/microconfig/utils/Os.java
  class Os (line 8) | @RequiredArgsConstructor(access = PRIVATE)
    method isWindows (line 12) | public static boolean isWindows() {

FILE: utils/src/main/java/io/microconfig/utils/StreamUtils.java
  class StreamUtils (line 17) | @RequiredArgsConstructor(access = PRIVATE)
    method forEach (line 19) | public static <K, V> List<V> forEach(Collection<K> collection,
    method forEach (line 24) | public static <K, V> List<V> forEach(Stream<K> stream,
    method forEach (line 29) | public static <K, V, T> T forEach(Collection<K> collection,
    method flatMapEach (line 35) | public static <K, V> List<V> flatMapEach(Collection<K> collection,
    method filter (line 42) | public static <T> List<T> filter(Collection<T> collection,
    method not (line 47) | public static <T> Predicate<T> not(Predicate<T> target) {
    method filter (line 51) | public static <K, T> T filter(Collection<K> collection,
    method findFirstResult (line 59) | public static <K, V> Optional<V> findFirstResult(Collection<K> collect...
    method toLinkedMap (line 67) | public static <T, K, U> Collector<T, ?, Map<K, U>> toLinkedMap(Functio...
    method toSortedMap (line 72) | public static <T, K, U> Collector<T, ?, SortedMap<K, U>> toSortedMap(F...
    method throwingMerger (line 77) | private static <T> BinaryOperator<T> throwingMerger() {

FILE: utils/src/main/java/io/microconfig/utils/StringUtils.java
  class StringUtils (line 17) | @RequiredArgsConstructor(access = PRIVATE)
    method isEmpty (line 19) | public static boolean isEmpty(String str) {
    method split (line 23) | public static List<String> split(String value, String separator) {
    method splitKeyValue (line 31) | public static Map<String, String> splitKeyValue(String... keyValue) {
    method findFirstIndexIn (line 37) | public static int findFirstIndexIn(String keyValue, String chars) {
    method addOffsets (line 46) | public static String addOffsets(String value, int spacesCount) {
    method dotCountIn (line 54) | public static long dotCountIn(String line) {
    method symbolCountIn (line 58) | public static long symbolCountIn(String line, char symbol) {
    method unixLikePath (line 62) | public static String unixLikePath(String path) {
    method toUnixPathSeparator (line 66) | public static String toUnixPathSeparator(String line) {
    method escape (line 70) | public static String escape(String value) {
    method asStringBuilder (line 76) | public static StringBuilder asStringBuilder(CharSequence line) {
    method getCauseMessage (line 80) | public static String getCauseMessage(Throwable t) {
    method getExceptionMessage (line 84) | public static String getExceptionMessage(Throwable t) {
    method isBlank (line 90) | public static boolean isBlank(String line) {

FILE: utils/src/test/java/io/microconfig/io/DumpedFsReaderTest.java
  class DumpedFsReaderTest (line 13) | class DumpedFsReaderTest {
    method readFully (line 16) | @Test
    method readLines (line 23) | @Test
    method firstLineOf (line 28) | @Test

FILE: utils/src/test/java/io/microconfig/utils/CacheProxyTest.java
  class CacheProxyTest (line 14) | class CacheProxyTest {
    method testCache (line 15) | @Test
    method testThrows (line 28) | @Test

FILE: utils/src/test/java/io/microconfig/utils/CollectionUtilsTest.java
  class CollectionUtilsTest (line 16) | class CollectionUtilsTest {
    method testSingleValue (line 17) | @Test
    method testJoin (line 24) | @Test
    method testMinus (line 43) | @Test
    method testSetOf (line 51) | @Test

FILE: utils/src/test/java/io/microconfig/utils/ConsoleColorTest.java
  class ConsoleColorTest (line 8) | class ConsoleColorTest {
    method test (line 9) | @Test

FILE: utils/src/test/java/io/microconfig/utils/FileUtilsTest.java
  class FileUtilsTest (line 11) | class FileUtilsTest {
    method nameAndExtension (line 12) | @Test

FILE: utils/src/test/java/io/microconfig/utils/IoUtilsTest.java
  class IoUtilsTest (line 15) | public class IoUtilsTest {
    method testReadFully (line 16) | @Test
    method testReadLines (line 24) | @Test
    method resourceFile (line 29) | public static File resourceFile() {

FILE: utils/src/test/java/io/microconfig/utils/StreamUtilsTest.java
  class StreamUtilsTest (line 18) | class StreamUtilsTest {
    method testForEach (line 21) | @Test
    method testFlatMapEach (line 29) | @Test
    method testFilter (line 37) | @Test
    method testFindFirstResult (line 43) | @Test
    method testToMap (line 49) | @Test
    method testToMapNotUniqueKey (line 61) | @Test

FILE: utils/src/test/java/io/microconfig/utils/StringUtilsTest.java
  class StringUtilsTest (line 14) | class StringUtilsTest {
    method testIsEmpty (line 15) | @Test
    method testSplit (line 23) | @Test
    method testSplitKeyValue (line 31) | @Test
    method testFindFirstIndexIn (line 43) | @Test
    method testAddOffsets (line 51) | @Test
    method testSymbolCount (line 57) | @Test
    method testUnixLikePath (line 68) | @Test
    method testEscape (line 73) | @Test
    method testAsStringBuilder (line 78) | @Test
Condensed preview — 518 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (504K chars).
[
  {
    "path": ".github/scripts/decrypt_secring.sh",
    "chars": 230,
    "preview": "#!/bin/sh\n\nmkdir $HOME/secrets\n# --batch to prevent interactive command --yes to assume \"yes\" for questions\ngpg --quiet "
  },
  {
    "path": ".github/scripts/native/Dockerfile-alpine",
    "chars": 231,
    "preview": "FROM ghcr.io/graalvm/native-image:muslib-22 AS builder\n\nWORKDIR /\n\nADD microconfig.jar /microconfig.jar\nRUN native-image"
  },
  {
    "path": ".github/scripts/native/graalvm-linux.sh",
    "chars": 350,
    "preview": "curl -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_linux-x6"
  },
  {
    "path": ".github/scripts/native/graalvm-mac.sh",
    "chars": 364,
    "preview": "curl -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_macos-x6"
  },
  {
    "path": ".github/scripts/native/graalvm-win.sh",
    "chars": 325,
    "preview": "curl -sL https://github.com/graalvm/graalvm-ce-builds/releases/download/jdk-21.0.2/graalvm-community-jdk-21.0.2_windows-"
  },
  {
    "path": ".github/scripts/native/native.bat",
    "chars": 145,
    "preview": "call \"C:\\Program Files\\Microsoft Visual Studio\\2022\\Enterprise\\VC\\Auxiliary\\Build\\vcvars64.bat\"\ngraalvm\\bin\\native-image"
  },
  {
    "path": ".github/scripts/native/native.sh",
    "chars": 53,
    "preview": "ls -lh\n.graalvm/bin/native-image -jar microconfig.jar"
  },
  {
    "path": ".github/scripts/set_gradle_properties.sh",
    "chars": 108,
    "preview": "sed \"s+$1=+$1=$2+g\" gradle.properties > gradle.properties.tmp && mv gradle.properties.tmp gradle.properties\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "chars": 484,
    "preview": "name: Multi OS Build\n\non:\n  push:\n    branches: [ master ]\n\njobs:\n  build:\n    runs-on: ${{matrix.os}}\n    strategy:\n   "
  },
  {
    "path": ".github/workflows/gradlepublish.yml",
    "chars": 1685,
    "preview": "name: Publish to Maven Central Staging\n\non:\n  push:\n    tags:\n      - 'v*'\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n "
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 6703,
    "preview": "name: \"Build Release\"\n\non:\n  push:\n    tags:\n      - 'v*'\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    name: \"Build Ja"
  },
  {
    "path": ".gitignore",
    "chars": 201,
    "preview": "*.ipr\n*.iml\n*.iws\n.idea/\n.bash_history\n.bash_logout\n.bash_profile\n.bashrc\n.emacs\n.lesshst\n.ssh/\n.viminfo\n.vimrc\n.project"
  },
  {
    "path": ".travis.yml",
    "chars": 253,
    "preview": "language: java\ndist: trusty\njdk: openjdk9\n\naddons:\n  sonarcloud:\n    organization: \"microconfig\"\n    token: 73371217f9b0"
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 41938,
    "preview": "# Quick start\n\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/"
  },
  {
    "path": "agent.sh",
    "chars": 282,
    "preview": ".graalvm/bin/java -agentlib:native-image-agent=config-merge-dir=microconfig-cli/src/main/resources/META-INF/native-image"
  },
  {
    "path": "build.gradle",
    "chars": 2114,
    "preview": "apply from: 'lib.gradle'\napply from: 'pomSettings.gradle'\n\nbuildscript {\n    repositories {\n        mavenCentral()\n     "
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 203,
    "preview": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributi"
  },
  {
    "path": "gradle.properties",
    "chars": 196,
    "preview": "version=4.9.5\n\norg.gradle.daemon=true\norg.gradle.jvmargs=-Dfile.encoding\\=UTF-8\norg.gradle.parallel=true\n\nossrhUsername="
  },
  {
    "path": "gradlew",
    "chars": 5296,
    "preview": "#!/usr/bin/env sh\n\n##############################################################################\n##\n##  Gradle start up"
  },
  {
    "path": "gradlew.bat",
    "chars": 2176,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
  },
  {
    "path": "lib.gradle",
    "chars": 645,
    "preview": "ext {\n    lib = [\n            spring_bom: \"org.springframework.boot:spring-boot-dependencies:3.3.3\",\n            lombok "
  },
  {
    "path": "lombok.config",
    "chars": 92,
    "preview": "lombok.anyConstructor.addConstructorProperties=true\nlombok.addLombokGeneratedAnnotation=true"
  },
  {
    "path": "microconfig-api/build.gradle",
    "chars": 53,
    "preview": "dependencies {\n    implementation project(':utils')\n}"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/configtypes/ConfigType.java",
    "chars": 192,
    "preview": "package io.microconfig.core.configtypes;\n\nimport java.util.Set;\n\npublic interface ConfigType {\n    String getName();\n\n  "
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/configtypes/ConfigTypeFilter.java",
    "chars": 170,
    "preview": "package io.microconfig.core.configtypes;\n\nimport java.util.List;\n\npublic interface ConfigTypeFilter {\n    List<ConfigTyp"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/configtypes/ConfigTypeFilters.java",
    "chars": 2496,
    "preview": "package io.microconfig.core.configtypes;\n\nimport lombok.RequiredArgsConstructor;\n\nimport java.io.File;\nimport java.util."
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/configtypes/ConfigTypeRepository.java",
    "chars": 146,
    "preview": "package io.microconfig.core.configtypes;\n\nimport java.util.List;\n\npublic interface ConfigTypeRepository {\n    List<Confi"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/environments/Component.java",
    "chars": 323,
    "preview": "package io.microconfig.core.environments;\n\nimport io.microconfig.core.configtypes.ConfigTypeFilter;\nimport io.microconfi"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/environments/ComponentGroup.java",
    "chars": 253,
    "preview": "package io.microconfig.core.environments;\n\nimport java.util.Optional;\n\npublic interface ComponentGroup {\n    String getN"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/environments/Components.java",
    "chars": 295,
    "preview": "package io.microconfig.core.environments;\n\nimport io.microconfig.core.configtypes.ConfigTypeFilter;\nimport io.microconfi"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/environments/Environment.java",
    "chars": 741,
    "preview": "package io.microconfig.core.environments;\n\nimport java.io.File;\nimport java.util.List;\nimport java.util.Optional;\n\npubli"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/environments/EnvironmentRepository.java",
    "chars": 296,
    "preview": "package io.microconfig.core.environments;\n\nimport java.util.List;\nimport java.util.Set;\n\npublic interface EnvironmentRep"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/exceptions/MicroconfigException.java",
    "chars": 342,
    "preview": "package io.microconfig.core.exceptions;\n\nimport lombok.NoArgsConstructor;\n\n@NoArgsConstructor\npublic class MicroconfigEx"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/properties/ConfigFormat.java",
    "chars": 177,
    "preview": "package io.microconfig.core.properties;\n\npublic enum ConfigFormat {\n    YAML,\n    PROPERTIES;\n\n    public String extensi"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/properties/DeclaringComponent.java",
    "chars": 166,
    "preview": "package io.microconfig.core.properties;\n\npublic interface DeclaringComponent {\n    String getConfigType();\n\n    String g"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/properties/PlaceholderResolveStrategy.java",
    "chars": 230,
    "preview": "package io.microconfig.core.properties;\n\nimport java.util.Optional;\n\npublic interface PlaceholderResolveStrategy {\n    O"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/properties/Properties.java",
    "chars": 836,
    "preview": "package io.microconfig.core.properties;\n\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimpor"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/properties/PropertiesFactory.java",
    "chars": 433,
    "preview": "package io.microconfig.core.properties;\n\nimport io.microconfig.core.configtypes.ConfigType;\n\nimport java.util.List;\n\npub"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/properties/Property.java",
    "chars": 292,
    "preview": "package io.microconfig.core.properties;\n\npublic interface Property {\n    String getKey();\n\n    String getValue();\n\n    b"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/properties/PropertySerializer.java",
    "chars": 440,
    "preview": "package io.microconfig.core.properties;\n\nimport io.microconfig.core.configtypes.ConfigType;\nimport io.microconfig.core.t"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/properties/Resolver.java",
    "chars": 163,
    "preview": "package io.microconfig.core.properties;\n\npublic interface Resolver {\n    String resolve(String value, DeclaringComponent"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/properties/TypedProperties.java",
    "chars": 904,
    "preview": "package io.microconfig.core.properties;\n\nimport io.microconfig.core.configtypes.ConfigType;\nimport io.microconfig.core.t"
  },
  {
    "path": "microconfig-api/src/main/java/io/microconfig/core/templates/Template.java",
    "chars": 227,
    "preview": "package io.microconfig.core.templates;\n\nimport java.io.File;\n\npublic interface Template {\n    File getSource();\n\n    Fil"
  },
  {
    "path": "microconfig-api/src/test/java/io/microconfig/core/configtypes/ConfigTypeFiltersTest.java",
    "chars": 2549,
    "preview": "package io.microconfig.core.configtypes;\n\nimport org.junit.jupiter.api.Test;\n\nimport java.io.File;\nimport java.util.List"
  },
  {
    "path": "microconfig-api/src/test/java/io/microconfig/core/properties/ConfigFormatTest.java",
    "chars": 448,
    "preview": "package io.microconfig.core.properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport static io.microconfig.core.propertie"
  },
  {
    "path": "microconfig-cli/build.gradle",
    "chars": 916,
    "preview": "apply plugin: 'application'\napply plugin: 'maven-publish'\napply plugin: 'com.github.johnrengelman.shadow'\n\nmainClassName"
  },
  {
    "path": "microconfig-cli/src/main/java/io/microconfig/CommandLineParamParser.java",
    "chars": 1939,
    "preview": "package io.microconfig;\n\nimport lombok.RequiredArgsConstructor;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport"
  },
  {
    "path": "microconfig-cli/src/main/java/io/microconfig/MicroconfigMain.java",
    "chars": 3998,
    "preview": "package io.microconfig;\n\nimport io.microconfig.core.MicroconfigRunner;\nimport io.microconfig.core.properties.Properties;"
  },
  {
    "path": "microconfig-cli/src/main/java/io/microconfig/MicroconfigParams.java",
    "chars": 1732,
    "preview": "package io.microconfig;\n\nimport lombok.RequiredArgsConstructor;\n\nimport java.io.File;\nimport java.util.LinkedHashSet;\nim"
  },
  {
    "path": "microconfig-cli/src/main/resources/META-INF/native-image/jni-config.json",
    "chars": 278,
    "preview": "[\n{\n  \"name\":\"java.lang.ClassLoader\",\n  \"methods\":[\n    {\"name\":\"getPlatformClassLoader\",\"parameterTypes\":[] }, \n    {\"n"
  },
  {
    "path": "microconfig-cli/src/main/resources/META-INF/native-image/native-image.properties",
    "chars": 1057,
    "preview": "Args = --no-fallback \\\n    --report-unsupported-elements-at-runtime \\\n    --initialize-at-build-time=io.microconfig.core"
  },
  {
    "path": "microconfig-cli/src/main/resources/META-INF/native-image/proxy-config.json",
    "chars": 499,
    "preview": "[\n  [\"io.microconfig.core.configtypes.ConfigTypeRepository\"],\n  [\"io.microconfig.core.environments.ComponentFactory\"],\n "
  },
  {
    "path": "microconfig-cli/src/main/resources/META-INF/native-image/reflect-config.json",
    "chars": 2542,
    "preview": "[\n{\n  \"name\":\"com.oracle.truffle.api.TruffleLanguage\"\n},\n{\n  \"name\":\"com.oracle.truffle.api.debug.impl.DebuggerInstrumen"
  },
  {
    "path": "microconfig-cli/src/main/resources/META-INF/native-image/resource-config.json",
    "chars": 667,
    "preview": "{\n  \"resources\":[\n    {\"pattern\":\"\\\\QMETA-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat\\\\E\"}, \n    "
  },
  {
    "path": "microconfig-cli/src/main/resources/log4j2.xml",
    "chars": 158,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Configuration status=\"fatal\">\n    <Loggers>\n        <Root level=\"OFF\">\n        <"
  },
  {
    "path": "microconfig-cli/src/test/java/io/microconfig/CommandLineParamParserTest.java",
    "chars": 816,
    "preview": "package io.microconfig;\n\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimport static java.u"
  },
  {
    "path": "microconfig-cli/src/test/java/io/microconfig/MicroconfigMainTest.java",
    "chars": 3922,
    "preview": "package io.microconfig;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\nimport org.junit.ju"
  },
  {
    "path": "microconfig-cli/src/test/java/io/microconfig/MicroconfigParamsTest.java",
    "chars": 1861,
    "preview": "package io.microconfig;\n\nimport org.junit.jupiter.api.Test;\n\nimport java.io.File;\nimport java.util.LinkedHashSet;\n\nimpor"
  },
  {
    "path": "microconfig-cli/src/test/resources/repo/components/component/application.yaml",
    "chars": 16,
    "preview": "key: application"
  },
  {
    "path": "microconfig-cli/src/test/resources/repo/components/component/os.deploy",
    "chars": 11,
    "preview": "key: deploy"
  },
  {
    "path": "microconfig-cli/src/test/resources/repo/envs/env1.yaml",
    "chars": 63,
    "preview": "group:\n  components:\n    - component\n    - component2:component"
  },
  {
    "path": "microconfig-cli/src/test/resources/repo/envs/env2.yaml",
    "chars": 63,
    "preview": "group:\n  components:\n    - component\n    - component2:component"
  },
  {
    "path": "microconfig-cli/src/test/resources/repo/envs/env3.yaml",
    "chars": 63,
    "preview": "group:\n  components:\n    - component\n    - component2:component"
  },
  {
    "path": "microconfig-core/build.gradle",
    "chars": 222,
    "preview": "apply plugin: 'java-library'\n\ndependencies {\n    api project(':microconfig-api')\n\n    implementation project(':utils'),\n"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/Microconfig.java",
    "chars": 8424,
    "preview": "package io.microconfig.core;\n\nimport io.microconfig.core.configtypes.ConfigTypeRepository;\nimport io.microconfig.core.co"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/MicroconfigRunner.java",
    "chars": 1585,
    "preview": "package io.microconfig.core;\n\nimport io.microconfig.core.properties.Properties;\nimport io.microconfig.core.properties.Pr"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/configtypes/CompositeConfigTypeRepository.java",
    "chars": 818,
    "preview": "package io.microconfig.core.configtypes;\n\nimport lombok.RequiredArgsConstructor;\n\nimport java.util.List;\n\nimport static "
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/configtypes/ConfigTypeImpl.java",
    "chars": 1077,
    "preview": "package io.microconfig.core.configtypes;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\nimport lombok.ToS"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/configtypes/CustomConfigTypeRepository.java",
    "chars": 3157,
    "preview": "package io.microconfig.core.configtypes;\n\nimport io.microconfig.io.FsReader;\nimport lombok.RequiredArgsConstructor;\nimpo"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/configtypes/StandardConfigType.java",
    "chars": 789,
    "preview": "package io.microconfig.core.configtypes;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\n\nimport java.util"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/configtypes/StandardConfigTypeRepository.java",
    "chars": 369,
    "preview": "package io.microconfig.core.configtypes;\n\nimport java.util.List;\n\nimport static java.util.Arrays.asList;\n\npublic class S"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/environments/ComponentFactory.java",
    "chars": 158,
    "preview": "package io.microconfig.core.environments;\n\npublic interface ComponentFactory {\n    Component createComponent(String name"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/environments/ComponentFactoryImpl.java",
    "chars": 739,
    "preview": "package io.microconfig.core.environments;\n\nimport io.microconfig.core.configtypes.ConfigTypeRepository;\nimport io.microc"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/environments/ComponentGroupImpl.java",
    "chars": 826,
    "preview": "package io.microconfig.core.environments;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstructor;\n\nimport java.uti"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/environments/ComponentImpl.java",
    "chars": 1198,
    "preview": "package io.microconfig.core.environments;\n\nimport io.microconfig.core.configtypes.ConfigType;\nimport io.microconfig.core"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/environments/ComponentsImpl.java",
    "chars": 966,
    "preview": "package io.microconfig.core.environments;\n\nimport io.microconfig.core.configtypes.ConfigTypeFilter;\nimport io.microconfi"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/environments/EnvironmentImpl.java",
    "chars": 4640,
    "preview": "package io.microconfig.core.environments;\n\nimport io.microconfig.core.properties.PropertiesFactory;\nimport io.microconfi"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/environments/repository/ComponentDefinition.java",
    "chars": 853,
    "preview": "package io.microconfig.core.environments.repository;\n\nimport io.microconfig.core.environments.Component;\nimport io.micro"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/environments/repository/ComponentGroupDefinition.java",
    "chars": 2917,
    "preview": "package io.microconfig.core.environments.repository;\n\nimport io.microconfig.core.environments.ComponentFactory;\nimport i"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/environments/repository/EnvInclude.java",
    "chars": 3021,
    "preview": "package io.microconfig.core.environments.repository;\n\nimport lombok.RequiredArgsConstructor;\nimport lombok.val;\n\nimport "
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/environments/repository/EnvironmentDefinition.java",
    "chars": 2315,
    "preview": "package io.microconfig.core.environments.repository;\n\nimport io.microconfig.core.environments.ComponentFactory;\nimport i"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/environments/repository/EnvironmentException.java",
    "chars": 551,
    "preview": "package io.microconfig.core.environments.repository;\n\nimport io.microconfig.core.exceptions.MicroconfigException;\n\nimpor"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/environments/repository/EnvironmentFile.java",
    "chars": 5823,
    "preview": "package io.microconfig.core.environments.repository;\n\nimport com.google.gson.Gson;\nimport io.microconfig.io.FsReader;\nim"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/environments/repository/FileEnvironmentRepository.java",
    "chars": 4853,
    "preview": "package io.microconfig.core.environments.repository;\n\nimport io.microconfig.core.environments.ComponentFactory;\nimport i"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/environments/repository/LazyInitEnvRepository.java",
    "chars": 318,
    "preview": "package io.microconfig.core.environments.repository;\n\nimport io.microconfig.core.environments.EnvironmentRepository;\nimp"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/DeclaringComponentImpl.java",
    "chars": 689,
    "preview": "package io.microconfig.core.properties;\n\nimport lombok.EqualsAndHashCode;\nimport lombok.Getter;\nimport lombok.RequiredAr"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/FileBasedComponent.java",
    "chars": 1239,
    "preview": "package io.microconfig.core.properties;\n\nimport lombok.EqualsAndHashCode;\nimport lombok.Getter;\nimport lombok.RequiredAr"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/OverrideProperty.java",
    "chars": 1985,
    "preview": "package io.microconfig.core.properties;\n\nimport lombok.EqualsAndHashCode;\nimport lombok.Getter;\nimport lombok.RequiredAr"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/PropertiesFactoryImpl.java",
    "chars": 1455,
    "preview": "package io.microconfig.core.properties;\n\nimport io.microconfig.core.configtypes.ConfigType;\nimport lombok.RequiredArgsCo"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/PropertiesImpl.java",
    "chars": 2797,
    "preview": "package io.microconfig.core.properties;\n\nimport lombok.EqualsAndHashCode;\nimport lombok.RequiredArgsConstructor;\n\nimport"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/PropertiesRepository.java",
    "chars": 357,
    "preview": "package io.microconfig.core.properties;\n\nimport io.microconfig.core.configtypes.ConfigType;\n\nimport java.util.Map;\n\npubl"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/PropertyImpl.java",
    "chars": 2544,
    "preview": "package io.microconfig.core.properties;\n\nimport lombok.EqualsAndHashCode;\nimport lombok.Getter;\nimport lombok.RequiredAr"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/ResolveException.java",
    "chars": 1767,
    "preview": "package io.microconfig.core.properties;\n\nimport io.microconfig.core.exceptions.MicroconfigException;\nimport lombok.Sette"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/TypedPropertiesImpl.java",
    "chars": 4234,
    "preview": "package io.microconfig.core.properties;\n\nimport io.microconfig.core.configtypes.ConfigType;\nimport io.microconfig.core.p"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/io/AbstractConfigReader.java",
    "chars": 1208,
    "preview": "package io.microconfig.core.properties.io;\n\nimport io.microconfig.core.properties.Property;\nimport io.microconfig.io.FsR"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/io/ConfigIo.java",
    "chars": 171,
    "preview": "package io.microconfig.core.properties.io;\n\nimport java.io.File;\n\npublic interface ConfigIo {\n    ConfigReader readFrom("
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/io/ConfigReader.java",
    "chars": 337,
    "preview": "package io.microconfig.core.properties.io;\n\nimport io.microconfig.core.properties.Property;\n\nimport java.util.List;\nimpo"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/io/ConfigWriter.java",
    "chars": 333,
    "preview": "package io.microconfig.core.properties.io;\n\nimport io.microconfig.core.properties.Property;\n\nimport java.util.Collection"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/io/properties/PropertiesConfigIo.java",
    "chars": 667,
    "preview": "package io.microconfig.core.properties.io.properties;\n\nimport io.microconfig.core.properties.io.ConfigIo;\nimport io.micr"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/io/properties/PropertiesReader.java",
    "chars": 1765,
    "preview": "package io.microconfig.core.properties.io.properties;\n\nimport io.microconfig.core.properties.Property;\nimport io.microco"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/io/properties/PropertiesWriter.java",
    "chars": 1434,
    "preview": "package io.microconfig.core.properties.io.properties;\n\nimport io.microconfig.core.properties.Property;\nimport io.microco"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/io/selector/ConfigFormatDetector.java",
    "chars": 217,
    "preview": "package io.microconfig.core.properties.io.selector;\n\nimport io.microconfig.core.properties.ConfigFormat;\n\nimport java.io"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/io/selector/ConfigFormatDetectorImpl.java",
    "chars": 1635,
    "preview": "package io.microconfig.core.properties.io.selector;\n\nimport io.microconfig.core.properties.ConfigFormat;\nimport io.micro"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/io/selector/ConfigIoFactory.java",
    "chars": 823,
    "preview": "package io.microconfig.core.properties.io.selector;\n\nimport io.microconfig.core.properties.io.ConfigIo;\nimport io.microc"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/io/selector/ConfigIoSelector.java",
    "chars": 1229,
    "preview": "package io.microconfig.core.properties.io.selector;\n\nimport io.microconfig.core.properties.ConfigFormat;\nimport io.micro"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/io/yaml/YamlConfigIo.java",
    "chars": 643,
    "preview": "package io.microconfig.core.properties.io.yaml;\n\nimport io.microconfig.core.properties.io.ConfigIo;\nimport io.microconfi"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/io/yaml/YamlReader.java",
    "chars": 11534,
    "preview": "package io.microconfig.core.properties.io.yaml;\n\nimport io.microconfig.core.properties.FileBasedComponent;\nimport io.mic"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/io/yaml/YamlTree.java",
    "chars": 157,
    "preview": "package io.microconfig.core.properties.io.yaml;\n\nimport java.util.Map;\n\npublic interface YamlTree {\n    String toYaml(Ma"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/io/yaml/YamlTreeImpl.java",
    "chars": 5489,
    "preview": "package io.microconfig.core.properties.io.yaml;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/io/yaml/YamlWriter.java",
    "chars": 1403,
    "preview": "package io.microconfig.core.properties.io.yaml;\n\nimport io.microconfig.core.properties.Property;\nimport io.microconfig.c"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/repository/ComponentGraph.java",
    "chars": 442,
    "preview": "package io.microconfig.core.properties.repository;\n\nimport io.microconfig.core.configtypes.ConfigType;\n\nimport java.io.F"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/repository/ComponentGraphImpl.java",
    "chars": 3791,
    "preview": "package io.microconfig.core.properties.repository;\n\nimport io.microconfig.core.configtypes.ConfigType;\nimport lombok.Req"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/repository/ComponentNotFoundException.java",
    "chars": 889,
    "preview": "package io.microconfig.core.properties.repository;\n\nimport io.microconfig.core.exceptions.MicroconfigException;\nimport l"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/repository/CompositePropertiesRepository.java",
    "chars": 1473,
    "preview": "package io.microconfig.core.properties.repository;\n\nimport io.microconfig.core.configtypes.ConfigType;\nimport io.microco"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/repository/ConfigFile.java",
    "chars": 2855,
    "preview": "package io.microconfig.core.properties.repository;\n\nimport io.microconfig.core.properties.Property;\nimport io.microconfi"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/repository/EnvProfilesComponentGraph.java",
    "chars": 2351,
    "preview": "package io.microconfig.core.properties.repository;\n\nimport io.microconfig.core.configtypes.ConfigType;\nimport io.microco"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/repository/FilePropertiesRepository.java",
    "chars": 2828,
    "preview": "package io.microconfig.core.properties.repository;\n\nimport io.microconfig.core.configtypes.ConfigType;\nimport io.microco"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/repository/Include.java",
    "chars": 1098,
    "preview": "package io.microconfig.core.properties.repository;\n\nimport lombok.EqualsAndHashCode;\nimport lombok.Getter;\nimport lombok"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/repository/Includes.java",
    "chars": 1972,
    "preview": "package io.microconfig.core.properties.repository;\n\nimport lombok.RequiredArgsConstructor;\n\nimport java.util.List;\n\nimpo"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/repository/RawConfig.java",
    "chars": 2980,
    "preview": "package io.microconfig.core.properties.repository;\n\nimport io.microconfig.core.properties.OverrideProperty;\nimport io.mi"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/ChainedResolver.java",
    "chars": 785,
    "preview": "package io.microconfig.core.properties.resolvers;\n\nimport io.microconfig.core.properties.Resolver;\nimport lombok.Require"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/RecursiveResolver.java",
    "chars": 1080,
    "preview": "package io.microconfig.core.properties.resolvers;\n\nimport io.microconfig.core.properties.DeclaringComponent;\nimport io.m"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/expression/ExpressionEvaluator.java",
    "chars": 1176,
    "preview": "package io.microconfig.core.properties.resolvers.expression;\n\nimport lombok.RequiredArgsConstructor;\nimport org.springfr"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/expression/ExpressionResolver.java",
    "chars": 2152,
    "preview": "package io.microconfig.core.properties.resolvers.expression;\n\nimport io.microconfig.core.properties.DeclaringComponent;\n"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/expression/functions/CustomIoApi.java",
    "chars": 754,
    "preview": "package io.microconfig.core.properties.resolvers.expression.functions;\n\nimport java.io.File;\n\nimport static io.microconf"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/expression/functions/CustomStringApi.java",
    "chars": 1734,
    "preview": "package io.microconfig.core.properties.resolvers.expression.functions;\n\nimport java.util.regex.Matcher;\n\nimport static j"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/Placeholder.java",
    "chars": 1960,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder;\n\nimport io.microconfig.core.properties.DeclaringComponent;"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/PlaceholderBorders.java",
    "chars": 5687,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder;\n\nimport lombok.Getter;\nimport lombok.RequiredArgsConstruct"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/PlaceholderResolver.java",
    "chars": 5229,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder;\n\nimport io.microconfig.core.environments.EnvironmentReposi"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/component/ComponentProperty.java",
    "chars": 240,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.component;\n\nimport java.util.Optional;\n\npublic i"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/component/ComponentResolveStrategy.java",
    "chars": 1162,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.component;\n\nimport io.microconfig.core.propertie"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/component/properties/ComponentProperties.java",
    "chars": 1171,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.component.properties;\n\nimport io.microconfig.cor"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/component/properties/ConfigDirProperty.java",
    "chars": 1432,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.component.properties;\n\nimport io.microconfig.cor"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/component/properties/ConfigRootDirProperty.java",
    "chars": 768,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.component.properties;\n\nimport io.microconfig.cor"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/component/properties/NameProperty.java",
    "chars": 511,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.component.properties;\n\nimport io.microconfig.cor"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/component/properties/ResultDirProperty.java",
    "chars": 806,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.component.properties;\n\nimport io.microconfig.cor"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/composite/CompositeResolveStrategy.java",
    "chars": 937,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.composite;\n\nimport io.microconfig.core.propertie"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/environment/EnvProperty.java",
    "chars": 296,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.environment;\n\nimport io.microconfig.core.environ"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/environment/EnvironmentResolveStrategy.java",
    "chars": 1701,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.environment;\n\nimport io.microconfig.core.environ"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/environment/properties/ComponentOrderProperty.java",
    "chars": 1284,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.environment.properties;\n\nimport io.microconfig.c"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/environment/properties/EnvNameProperty.java",
    "chars": 576,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.environment.properties;\n\nimport io.microconfig.c"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/environment/properties/EnvironmentProperties.java",
    "chars": 725,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.environment.properties;\n\nimport io.microconfig.c"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/environment/properties/GroupNameProperty.java",
    "chars": 671,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.environment.properties;\n\nimport io.microconfig.c"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/environment/properties/IpProperty.java",
    "chars": 664,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.environment.properties;\n\nimport io.microconfig.c"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/environment/properties/PortOffsetProperty.java",
    "chars": 637,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.environment.properties;\n\nimport io.microconfig.c"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/standard/StandardResolveStrategy.java",
    "chars": 946,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.standard;\n\nimport io.microconfig.core.environmen"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/resolvers/placeholder/strategies/system/SystemResolveStrategy.java",
    "chars": 1962,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder.strategies.system;\n\nimport io.microconfig.core.properties.D"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/serializers/ConfigDiff.java",
    "chars": 2906,
    "preview": "package io.microconfig.core.properties.serializers;\n\nimport io.microconfig.core.properties.Property;\n\nimport java.io.Fil"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/serializers/ConfigResult.java",
    "chars": 2380,
    "preview": "package io.microconfig.core.properties.serializers;\n\nimport com.google.gson.Gson;\nimport io.microconfig.core.properties."
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/serializers/PropertySerializers.java",
    "chars": 4437,
    "preview": "package io.microconfig.core.properties.serializers;\n\nimport io.microconfig.core.configtypes.ConfigTypeImpl;\nimport io.mi"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/templates/BinaryTemplate.java",
    "chars": 912,
    "preview": "package io.microconfig.core.properties.templates;\n\nimport io.microconfig.core.templates.Template;\nimport lombok.Getter;\n"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/templates/MustacheTemplateProcessor.java",
    "chars": 1920,
    "preview": "package io.microconfig.core.properties.templates;\n\nimport com.samskivert.mustache.Mustache;\nimport com.samskivert.mustac"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/templates/StringTemplate.java",
    "chars": 4106,
    "preview": "package io.microconfig.core.properties.templates;\n\nimport io.microconfig.core.properties.DeclaringComponent;\nimport io.m"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/templates/TemplateContentPostProcessor.java",
    "chars": 323,
    "preview": "package io.microconfig.core.properties.templates;\n\nimport io.microconfig.core.properties.TypedProperties;\n\nimport java.i"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/templates/TemplateDefinition.java",
    "chars": 4236,
    "preview": "package io.microconfig.core.properties.templates;\n\nimport io.microconfig.core.properties.DeclaringComponent;\nimport io.m"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/templates/TemplateDefinitionParser.java",
    "chars": 260,
    "preview": "package io.microconfig.core.properties.templates;\n\nimport io.microconfig.core.properties.Property;\n\nimport java.util.Col"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/templates/TemplatePattern.java",
    "chars": 1888,
    "preview": "package io.microconfig.core.properties.templates;\n\nimport lombok.Builder;\nimport lombok.Getter;\nimport lombok.With;\n\nimp"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/templates/TemplatesService.java",
    "chars": 2531,
    "preview": "package io.microconfig.core.properties.templates;\n\nimport io.microconfig.core.properties.Property;\nimport io.microconfig"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/templates/definition/parser/ArrowNotationParser.java",
    "chars": 2751,
    "preview": "package io.microconfig.core.properties.templates.definition.parser;\n\nimport io.microconfig.core.properties.Property;\nimp"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/templates/definition/parser/FromToNotationParser.java",
    "chars": 1549,
    "preview": "package io.microconfig.core.properties.templates.definition.parser;\n\nimport io.microconfig.core.properties.Property;\nimp"
  },
  {
    "path": "microconfig-core/src/main/java/io/microconfig/core/properties/templates/definition/parser/SquareBracketsNotationParser.java",
    "chars": 2451,
    "preview": "package io.microconfig.core.properties.templates.definition.parser;\n\nimport io.microconfig.core.properties.Property;\nimp"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/ClasspathReader.java",
    "chars": 538,
    "preview": "package io.microconfig.core;\n\nimport org.springframework.core.io.ClassPathResource;\n\nimport java.io.File;\nimport java.io"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/MicroconfigRunnerTest.java",
    "chars": 1245,
    "preview": "package io.microconfig.core;\n\nimport io.microconfig.core.environments.repository.EnvironmentException;\nimport org.junit."
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/MicroconfigTest.java",
    "chars": 4273,
    "preview": "package io.microconfig.core;\n\nimport org.junit.jupiter.api.DynamicTest;\nimport org.junit.jupiter.api.Test;\nimport org.ju"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/TemplatesTest.java",
    "chars": 1604,
    "preview": "package io.microconfig.core;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.io.TempDir;\n\nimport java.i"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/configtypes/CompositeConfigTypeRepositoryTest.java",
    "chars": 1378,
    "preview": "package io.microconfig.core.configtypes;\n\nimport org.junit.jupiter.api.Test;\n\nimport java.util.List;\n\nimport static io.m"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/configtypes/ConfigTypeImplTest.java",
    "chars": 1317,
    "preview": "package io.microconfig.core.configtypes;\n\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Set;\n\nimport static io.mi"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/configtypes/CustomConfigTypeRepositoryTest.java",
    "chars": 1122,
    "preview": "package io.microconfig.core.configtypes;\n\nimport io.microconfig.io.DumpedFsReader;\nimport org.junit.jupiter.api.Test;\n\ni"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/configtypes/StandardConfigTypeRepositoryTest.java",
    "chars": 422,
    "preview": "package io.microconfig.core.configtypes;\n\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nimp"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/configtypes/StandardConfigTypeTest.java",
    "chars": 602,
    "preview": "package io.microconfig.core.configtypes;\n\nimport org.junit.jupiter.api.Test;\n\nimport static io.microconfig.core.configty"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/environments/ComponentFactoryImplTest.java",
    "chars": 931,
    "preview": "package io.microconfig.core.environments;\n\nimport io.microconfig.core.configtypes.ConfigTypeRepository;\nimport io.microc"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/environments/ComponentGroupImplTest.java",
    "chars": 1520,
    "preview": "package io.microconfig.core.environments;\n\nimport org.junit.jupiter.api.Test;\n\nimport static java.util.Arrays.asList;\nim"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/environments/ComponentImplTest.java",
    "chars": 1603,
    "preview": "package io.microconfig.core.environments;\n\nimport io.microconfig.core.configtypes.ConfigTypeFilter;\nimport io.microconfi"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/environments/ComponentsImplTest.java",
    "chars": 1886,
    "preview": "package io.microconfig.core.environments;\n\nimport io.microconfig.core.configtypes.ConfigTypeFilter;\nimport io.microconfi"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/environments/EnvironmentImplTest.java",
    "chars": 4781,
    "preview": "package io.microconfig.core.environments;\n\nimport io.microconfig.core.properties.PropertiesFactory;\nimport io.microconfi"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/environments/repository/ComponentDefinitionTest.java",
    "chars": 1213,
    "preview": "package io.microconfig.core.environments.repository;\n\nimport io.microconfig.core.environments.Component;\nimport io.micro"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/environments/repository/FileEnvironmentRepositoryTest.java",
    "chars": 7966,
    "preview": "package io.microconfig.core.environments.repository;\n\nimport io.microconfig.core.configtypes.ConfigTypeRepository;\nimpor"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/ComponentWithEnvTest.java",
    "chars": 349,
    "preview": "package io.microconfig.core.properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter.api.Asserti"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/FileBasedComponentTest.java",
    "chars": 975,
    "preview": "package io.microconfig.core.properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport java.io.File;\n\nimport static io.micr"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/PropertiesImplTest.java",
    "chars": 3758,
    "preview": "package io.microconfig.core.properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport java.util.Optional;\nimport java.util"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/PropertyImplTest.java",
    "chars": 3035,
    "preview": "package io.microconfig.core.properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport java.io.File;\n\nimport static io.micr"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/ResolveExceptionTest.java",
    "chars": 1956,
    "preview": "package io.microconfig.core.properties;\n\nimport org.junit.jupiter.api.Test;\n\nimport static io.microconfig.core.propertie"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/TypedPropertiesImplTest.java",
    "chars": 3943,
    "preview": "package io.microconfig.core.properties;\n\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.Test;\n\nim"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/io/properties/PropertiesConfigIoTest.java",
    "chars": 1393,
    "preview": "package io.microconfig.core.properties.io.properties;\n\nimport io.microconfig.io.DumpedFsReader;\nimport org.junit.jupiter"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/io/yaml/YamlConfigIoTest.java",
    "chars": 4046,
    "preview": "package io.microconfig.core.properties.io.yaml;\n\nimport io.microconfig.core.properties.FileBasedComponent;\nimport io.mic"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/io/yaml/YamlTreeImplTest.java",
    "chars": 2959,
    "preview": "package io.microconfig.core.properties.io.yaml;\n\nimport io.microconfig.io.DumpedFsReader;\nimport org.junit.jupiter.api.T"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/repository/ComponentNotFoundExceptionTest.java",
    "chars": 661,
    "preview": "package io.microconfig.core.properties.repository;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.junit.jupiter."
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/repository/CompositePropertiesRepositoryTest.java",
    "chars": 3013,
    "preview": "package io.microconfig.core.properties.repository;\n\nimport io.microconfig.core.properties.PropertiesRepository;\nimport i"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/repository/EnvProfilesComponentGraphTest.java",
    "chars": 3954,
    "preview": "package io.microconfig.core.properties.repository;\n\nimport io.microconfig.core.environments.Environment;\nimport io.micro"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/repository/IncludeTest.java",
    "chars": 939,
    "preview": "package io.microconfig.core.properties.repository;\n\nimport org.junit.jupiter.api.Test;\n\nimport static io.microconfig.cor"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/resolvers/expression/ExpressionResolverTest.java",
    "chars": 1349,
    "preview": "package io.microconfig.core.properties.resolvers.expression;\n\nimport io.microconfig.core.properties.resolvers.RecursiveR"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/resolvers/expression/functions/CustomStringApiTest.java",
    "chars": 1469,
    "preview": "package io.microconfig.core.properties.resolvers.expression.functions;\n\nimport org.junit.jupiter.api.Test;\n\nimport stati"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/resolvers/placeholder/PlaceholderBordersTest.java",
    "chars": 1155,
    "preview": "package io.microconfig.core.properties.resolvers.placeholder;\n\nimport org.junit.jupiter.api.Test;\n\nimport static org.jun"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/templates/StringTemplatePatternTest.java",
    "chars": 1165,
    "preview": "package io.microconfig.core.properties.templates;\n\nimport org.junit.jupiter.api.Test;\n\nimport static io.microconfig.core"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/templates/StringTemplateTest.java",
    "chars": 3752,
    "preview": "package io.microconfig.core.properties.templates;\n\nimport io.microconfig.core.properties.DeclaringComponent;\nimport io.m"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/templates/definition/parser/ArrowNotationParserTest.java",
    "chars": 2960,
    "preview": "package io.microconfig.core.properties.templates.definition.parser;\n\nimport io.microconfig.core.properties.DeclaringComp"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/templates/definition/parser/FromToNotationParserTest.java",
    "chars": 1963,
    "preview": "package io.microconfig.core.properties.templates.definition.parser;\n\nimport io.microconfig.core.properties.DeclaringComp"
  },
  {
    "path": "microconfig-core/src/test/java/io/microconfig/core/properties/templates/definition/parser/SquareBracketsNotationParserTest.java",
    "chars": 2255,
    "preview": "package io.microconfig.core.properties.templates.definition.parser;\n\nimport io.microconfig.core.properties.DeclaringComp"
  },
  {
    "path": "microconfig-core/src/test/resources/configFormats/properties/propLine.properties",
    "chars": 207,
    "preview": "p=p_v\np2:p2_v\np3:=p3_v\np4=:p4_v\n#comment=value\njwt.publicKey=-----BEGIN PUBLIC KEY-----\\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8"
  }
]

// ... and 318 more files (download for full content)

About this extraction

This page contains the full source code of the microconfig/microconfig GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 518 files (416.5 KB), approximately 116.2k tokens, and a symbol index with 1058 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!